External Publication
Visit Post

ANN: pGenie – a SQL-first code generator for PostgreSQL: no DSLs, no ORMs, no hand-rolled codecs

Haskell Community [Unofficial] April 2, 2026
Source

This looks great! Maybe I’m being pedantic, but one thing that often irks me about database library docs is that they try and pretend like we can infer domain types from the database schema.

Consider

data TrackInfo = TrackInfo
  { -- | Maps to @title@.
    title :: Maybe (Text),
    -- | Maps to @duration_seconds@.
    durationSeconds :: Maybe (Int32),
    -- | Maps to @tags@.
    tags :: Maybe (Vector (Maybe Text))
  }
  deriving stock (Show, Eq, Ord)

Personally, I’d much rather see this called TrackInfoRow (or even TrackInfoPgRow) and be explicit that this is a representation of a database row. It may seem like a tiny change, but it makes it clear that the intention is to be as precise as you can be in representing your row , and not in modeling the domain.

Otherwise tags :: Maybe (Vector (Maybe Text)) just seems hideous – in the real world you’ll probably want to have something like tags :: Set Text which is easier to read, more ergonomic and also more correct, because you’re unlikely to want to have duplicate tags.

Also, adding the Row suffix makes it clear that you have to think and actually model your domain type based on the problem you’re solving rather than the database details.

Discussion in the ATmosphere

Loading comments...