package store
import (
"context"
"database/sql"
)
type Queries struct {
db *sql.DB
getByEmail *sql.Stmt
}
func New(db *sql.DB) (*Queries, error) {
stmt, err := db.Prepare(`SELECT id FROM users WHERE email = $1`)
if err != nil {
return nil, err
}
return &Queries{db: db, getByEmail: stmt}, nil
}
func (q *Queries) Close() error {
return q.getByEmail.Close()
}
func (q *Queries) UserIDByEmail(ctx context.Context, email string) (string, error) {
var id string
err := q.getByEmail.QueryRowContext(ctx, email).Scan(&id)
return id, err
}
Prepared statements are useful when the same query runs in hot loops, but they come with lifecycle responsibilities. I prepare once (usually at startup), store the *sql.Stmt, and always close it on shutdown. The important detail is still using QueryRowContext so deadlines and cancellations work; prepared statements don’t magically inherit context. This pattern is also safer than building SQL strings in loops and it can reduce parse overhead on the database side. In production, I pair this with context.WithTimeout at the handler layer and with metrics for query latency so slow queries are obvious. The example below shows a small wrapper that provides a typed method around a prepared statement, keeping call sites clean and consistent.
Related snips
package api
import (
"net/http"
"runtime/debug"
)
Expose build metadata for debugging deploys
package dbutil
import (
"context"
"github.com/jackc/pgconn"
Retry Postgres serialization failures with bounded attempts
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
Rails.application.configure do
config.after_initialize do
Bullet.enable = true
Bullet.alert = false
Bullet.bullet_logger = true
Bullet.console = true
N+1 query detection with Bullet gem
# BAD: N+1 query problem
@users = User.all
@users.each do |user|
puts user.posts.count # Fires query for each user!
end
ActiveRecord query optimization and N+1 prevention
json.array! @posts do |post|
json.cache! ['v1', post], expires_in: 1.hour do
json.id post.id
json.title post.title
json.excerpt post.excerpt
json.published_at post.published_at
Fragment caching for expensive JSON serialization
Share this code
Here's the card — post it anywhere.