I met with the creators/maintainers of sqlc the other day, and per their request (I promise this wasn’t me complaining randomly, as is usually the case), they asked about the project’s weaknesses. I sent over a few somewhat problematic queries, and of those, I think this is my favorite:

-- name: ClusterGetPage :many
SELECT *
FROM cluster
WHERE team_id = any(@team_id::uuid[])
    AND archived_at IS NULL
    AND parent_id IS NULL
    AND
        CASE WHEN @cursor_specified::boolean THEN
            CASE WHEN @by_id::boolean   AND NOT @descending::boolean THEN id::text    > @cursor_threshold::text
                 WHEN @by_id            AND     @descending          THEN id::text    < @cursor_threshold
                 WHEN @by_name::boolean AND NOT @descending          THEN lower(name) > lower(@cursor_threshold)
                 WHEN @by_name          AND     @descending          THEN lower(name) < lower(@cursor_threshold)
            END
        ELSE
            id = id
        END
ORDER BY
    CASE WHEN @by_id   AND NOT @descending THEN id          END ASC,
    CASE WHEN @by_id   AND     @descending THEN id          END DESC,
    CASE WHEN @by_name AND NOT @descending THEN lower(name) END ASC,
    CASE WHEN @by_name AND     @descending THEN lower(name) END DESC
LIMIT @max;

Unlike a more traditional ORM, sqlc can’t arbitrarily chain expressions. All the SQL that can be in the SQL is in the SQL, which means that any logical branching has to be done with CASE/WHEN expressions.

This monstrosity has a straightforward objective: listing, with pagination. But it does allow pagination along two dimensions (id and name), and with a cursor or without, which is where it gets a little gnarly.

That said, compared to pagination logic whose parts to build a complete query are littered across a half-dozen pagination utility modules, and whose totality is obscured by its piecemeal nature, maybe the sqlc version isn’t so bad?

View all atoms ⭢