Example from the sqlc creator (https://github.com/sqlc-dev/sqlc/discussions/364#discussionc...):
-- name: FilterFoo :many
SELECT * FROM foo
WHERE fk = @fk
AND (CASE WHEN @is_bar::bool THEN bar = @bar ELSE TRUE END)
AND (CASE WHEN @lk_bar::bool THEN bar LIKE @bar ELSE TRUE END)
AND (CASE WHEN @is_baz::bool THEN baz = @baz ELSE TRUE END)
AND (CASE WHEN @lk_baz::bool THEN baz LIKE @baz ELSE TRUE END)
ORDER BY
CASE WHEN @bar_asc::bool THEN bar END asc,
CASE WHEN @bar_desc::bool THEN bar END desc,
CASE WHEN @baz_asc::bool THEN baz END asc,
CASE WHEN @baz_desc::bool THEN baz END desc;sqlc lacking support for dynamic query generation is just absolutely baffling. Composition of query fragments is, like, one of the main reasons you use a query builder - it's very hard to do in raw SQL! If you don't need that feature, why are you even messing around with SQL code on the application side? Just write and call stored procedures in the database! People will think you're a time traveler from the 1980's but it works!
Golang's SQL ecosystem is... pretty miserable, really. I mean, I look at what jOOQ can do and I weep at the state of things over in go. In golang everything goes through database/sql because that's the "standard" solution, but database/sql is a huge mess with a long track record of disastrous bugs (like the possibility of accidentally running queries outside of the intended transaction) that makes it very hard to take advantage of feature-rich databases like postgres. pgx (postgres connection library) is actually quite good when you use its native API, but because everything has to go through the database/sql interface it gets pretty crippled with a lot of annoyances (try mapping postgres arrays or jsonb documents into structs and you'll see what I mean).
I can't get behind something like sqlc because if it doesn't support your language or SQL dialect or the feature you need you're worse off than not using it.
If you want to use a database-specific connector API, like pgx for postgres for example, you usually have to roll your own query execution (including parameter binding) and quite a lot of the result mapping too. I'd expect that to be a significant amount of work, but what's worse is that having that convenience done for you is a big reason for using a library like Jet in the first place.
So you're either stuck with the limitations of database/sql, or you don't get to enjoy a lot of the benefits that a mature database library brings. I don't like it.
I ended up adding custom value types to wrap our JSON (actually Protobuf) values: https://gist.github.com/Cyberax/07486a2264e29d95ed8c67e002f9... - we codegenerate them from Protobuf descriptions.
If Jet provided a tool to translate their API to/from SQL I might consider it though.
someJetStatement.DebugSql()
All Jet-generated Statement objects have the .DebugSql() method. It returns the generated query as a string with all the bound parameters inlined[0] so you can just print it or grab it with the debugger and copypaste it into your query console.[0]: that is, it translates the query it'd actually execute, which would look like
WHERE foo = $1
into WHERE foo = 'bound parameter value'
with some rudimentary escaping to avoid the most obvious SQL injection problems (don't use it to actually run queries in production, obviously!!).I mean if I start writing a complex query in a DB client and then want to translate it to Jet.