I was reading the whole article waiting to see this line, and the article did not disappoint. This is still the main reason I will stick with Rust or Crystal (depending on the use-case) and avoid Go if I can for the foreseeable future. Generics are just a must these days for non-trivial software projects. It's a shame too because Go has so much promise in other respects.
How We Went All In on sqlc/pgx for Postgres and Go
11–20 of 160 posts
Re: How We Went All In on sqlc/pgx for Postgres and Go
#12> I’ve largely covered sqlc’s objective benefits and features, but more subjectively, it just feels good and fast to work with. Like Go itself, the tool’s working for you instead of against you, and giving you an easy way to get work done without wrestling with the computer all day.
I've been meaning to write a blog post about sqlc myself, and when I get to it, I'll probably quote this line. sqlc is that rare tool that just "feels right". I think that feeling comes from a combination of things. It's fast. It uses an idiomatic Go approach (code generation, instead of e.g. reflection) to solve the problem at hand, so it feels at home in the Go ecosystem. As noted in the article, it allows you to check that your SQL is valid at compile-time, saving you from discovering errors at runtime, and eliminating the need for certain types of tests.
But perhaps most of all, sqlc lets you just write SQL. After using sqlc, using a more conventional ORM almost seemed like a crazy proposition. Why would someone author an ORM, painstakingly creating Go functions that just map to existing SQL features? Such a project is practically destined to be perpetually incomplete, and if one day it is no longer maintained, migration will be painful. And why add to your code a dependency on such a project, when you could use a tool like sqlc that is so drastically lighter, and brings nearly all the benefits?
sqlc embraces the idea that the right tool for talking to a relational database is the one we've had all along, the one which every engineer already knows: SQL. I look forward to using it in more projects.
Re: How We Went All In on sqlc/pgx for Postgres and Go
#13Re: How We Went All In on sqlc/pgx for Postgres and Go
#14As an aside - for anyone working with databases in Go, check out https://pkg.go.dev/modernc.org/sqlite It allows drop in replacement of SQLite that is in pure Go - no CGO or anything required for compilation, while still having everything implemented from SQLite. Insert speed is a bit lacking (about ~6x slower in my experience compared to the CGO sqlite3 package), but its good enough for me.
Just about all the code looks like this:
// Call this routine to record the fact that an OOM (out-of-memory) error
// has happened. This routine will set db->mallocFailed, and also
// temporarily disable the lookaside memory allocator and interrupt
// any running VDBEs.
func Xsqlite3OomFault(tls *libc.TLS, db uintptr) { /* sqlite3.c:28548:21: */
if (int32((*Sqlite3)(unsafe.Pointer(db)).FmallocFailed) == 0) &&
(int32((*Sqlite3)(unsafe.Pointer(db)).FbBenignMalloc) == 0) {
(*Sqlite3)(unsafe.Pointer(db)).FmallocFailed = U8(1)
if (*Sqlite3)(unsafe.Pointer(db)).FnVdbeExec > 0 {
libc.AtomicStoreNInt32((db + 400 /* &.u1 */ /* &.isInterrupted */), int32(1), 0)
}
(*Sqlite3)(unsafe.Pointer(db)).Flookaside.FbDisable++
(*Sqlite3)(unsafe.Pointer(db)).Flookaside.Fsz = U16(0)
if (*Sqlite3)(unsafe.Pointer(db)).FpParse != 0 {
(*Parse)(unsafe.Pointer((*Sqlite3)(unsafe.Pointer(db)).FpParse)).Frc = SQLITE_NOMEM
}
}
}Re: How We Went All In on sqlc/pgx for Postgres and Go
#15> However, without generics, Go’s type system can only offer so much I was reading the whole article waiting to see this line, and the article did not disappoint. This is still the main reason I will stick with Rust or Crystal (depending on the use-case) and avoid Go if I can for the foreseeable future. Generics are just a must these days for non-trivial software projects. It's a shame too because Go has so much prom…
For the thousands of devs shipping non-trivial code, keep going!
Re: How We Went All In on sqlc/pgx for Postgres and Go
#16Invent Go.
Waiting for generics....
5 year later
Go looks like Java. Back to square one :)
Re: How We Went All In on sqlc/pgx for Postgres and Go
#17Re: How We Went All In on sqlc/pgx for Postgres and Go
#18Other than that I like it a lot. I built some codegen stuff in the past for test automation and it's really quite nice because it reduces a lot of user errors.
Re: How We Went All In on sqlc/pgx for Postgres and Go
#19Proteus generates functions at runtime, avoiding code generation. Performance is identical to writing SQL mapping code yourself. I spoke about its implementation at GopherCon 2017: https://www.youtube.com/watch?v=hz6d7rzqJ6Q
Re: How We Went All In on sqlc/pgx for Postgres and Go
#20Needing to use arrays for the IN use case (see https://github.com/kyleconroy/sqlc/issues/216) and the bulk insert case feel like large divergences from what "idiomatic SQL" looks like. It means that you have to adjust how you write your queries. And that can be intimidating for new developers.
The conditional insert case also just doesn't look particularly elegant and the SQL query is pretty large.
sqlc also just doesn't look like it could help with very dynamic queries I need to generate - I work on a team that owns a little domain-specific search engine. The conditional approach could in theory with here, but it's not good for the query planner: https://use-the-index-luke.com/sql/where-clause/obfuscation/...