What it does
A person uploads a medical-claims spreadsheet with about 40 columns: members, dates, diagnosis and procedure codes, and billed, allowed and paid amounts. Then they ask things like "total paid by facility since June" in plain English. A model (Llama 3.3 on Groq by default, or GPT-4o or Gemini) writes the SQL, the server runs it on Postgres and returns the rows together with the SQL, so the answer can be checked.
Where it came from
I first built it as a paid prototype task for a health-data startup, in Next.js with Supabase. The CTO ran it locally and called it the best test of the candidates they tried. I then rewrote the backend in Go, keeping the same five endpoints and the same JSON, so the existing dashboard works against either one.
The problem with the first version
The prototype ran every generated query through a database function that would also run INSERT, UPDATE and DELETE. For a demo that was fine. For real claims data it means one bad model answer could change or wipe the table.
Two locks in the Go version
- A guard in code. The model's reply is parsed, and only a single SELECT or WITH query gets through. A second statement after a semicolon, a write hidden inside a WITH, or calls like pg_sleep are refused, and the person sees the refused SQL. Text inside quotes cannot trick it.
- A read-only transaction. Whatever passes the guard runs inside a READ ONLY transaction with a statement timeout and a row cap. A test pushes a DELETE straight past the guard to prove the database itself refuses it and the row count does not change.
Faster uploads
The prototype inserted rows 500 at a time through the Supabase client. The Go version streams rows out of the sheet and loads them with Postgres COPY in batches of 5,000. Measured on a MacBook with Postgres 18: 400,000 rows from a 21.7 MB sheet in 18.4 seconds, and an aggregate by facility over all of them in 262 ms.
Other changes
- Resetting the schema is off unless it is switched on, instead of open to anyone who can reach the endpoint.
- No anonymous insert, select or delete policies; the server uses its own database role.
- One 18 MB static binary and a small Docker image instead of a Node server.
Tests
Unit tests cover the SQL guard, the three model clients against a fake HTTP server, the spreadsheet column mapping and dates, and every HTTP endpoint. Integration tests start a real Postgres and run the upload, the queries, the read-only lock, the timeout and the 400,000-row speed run.
Stack
Go 1.27, pgx, excelize, Postgres or Supabase, Groq, OpenAI and Gemini APIs, Docker. Code: github.com/shabeebhasan/supaquery-go.
What it does not claim
It is a rewrite of a prototype, not a system in production. The model can still write a wrong query; that is why the SQL is always shown with the answer. The guard is a keyword check, and the read-only transaction is the real lock behind it.
Message me on the platform where you found this and I will answer there.