{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreih5yl6yktgiqdcjnis7rkef6uil6rhgmoe45xoaomypspjmzsxviu",
    "uri": "at://did:plc:pi6woz4d47bkuws673w2il2r/app.bsky.feed.post/3miixz27nyza2"
  },
  "path": "/t/ann-pgenie-a-sql-first-code-generator-for-postgresql-no-dsls-no-orms-no-hand-rolled-codecs/13869#post_2",
  "publishedAt": "2026-04-02T08:08:39.000Z",
  "site": "https://discourse.haskell.org",
  "tags": [
    "@title",
    "@duration_seconds",
    "@tags"
  ],
  "textContent": "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.\n\nConsider\n\n\n    data TrackInfo = TrackInfo\n      { -- | Maps to @title@.\n        title :: Maybe (Text),\n        -- | Maps to @duration_seconds@.\n        durationSeconds :: Maybe (Int32),\n        -- | Maps to @tags@.\n        tags :: Maybe (Vector (Maybe Text))\n      }\n      deriving stock (Show, Eq, Ord)\n\n\nPersonally, 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.\n\nOtherwise `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.\n\nAlso, 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.",
  "title": "ANN: pGenie – a SQL-first code generator for PostgreSQL: no DSLs, no ORMs, no hand-rolled codecs"
}