Live data from Hacker News

How We Went All In on sqlc/pgx for Postgres and Go

brandur.org

11–20 of 160 posts

Re: How We Went All In on sqlc/pgx for Postgres and Go

#11
> 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 promise in other respects.

Re: How We Went All In on sqlc/pgx for Postgres and Go

#12
From the article:

> 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

#14
post #4

As 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.

It's not really pure go, it's transpiled using https://gitlab.com/cznic/ccgo

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
post #11

> 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…

They're really not a `must`. What a silly comment - Docker and Kubernetes and substantial parts of Google wouldn't be classed as trivial.

For the thousands of devs shipping non-trivial code, keep going!

Re: How We Went All In on sqlc/pgx for Postgres and Go

#19
If you are looking for a way to map SQL queries to type safe Go functions, take a look at my library Proteus: https://github.com/jonbodner/proteus

Proteus 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

#20
I was really really excited when I saw the title because I've been having a lot of difficulties with other Go SQL libraries, but the caveats section gives me pause.

Needing 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/...

Post reply on HN