Get
Use db.Get to read zero or one database row into a typed Go value.
Get
Use db.Get when a query is expected to return zero or one row.
It scans a single row into a typed Go value and also tells you whether a row was found.
user, found, err := db.Get[User](ctx, conn, selectUserQuery, id)
if err != nil {
return User{}, false, err
}
if !found {
return User{}, false, nil
}Function
func Get[T any](ctx context.Context, c db.Conn, query string, args ...any) (T, bool, error)Get accepts:
- a
context.Context - a
db.Conn - a SQL or CQL query string
- optional query arguments
It returns:
T, found, errorfound is false when the query returns no rows.
When to Use Get
Use db.Get when:
- the query should return one row or no rows
- a missing row is a normal application case
- the result shape is known
- you want a typed Go value
- you are loading by ID, email, slug, token, or another lookup key
Define a Model
type User struct {
ID int64 `db:"id"`
Name string `db:"name"`
Email string `db:"email"`
Active bool `db:"active"`
CreatedAt time.Time `db:"created_at"`
}Query
For MySQL and Scylla, use ? placeholders.
const selectUserQuery = `
SELECT *
FROM users
WHERE id = ?
LIMIT 1
`For PostgreSQL, use numbered placeholders.
const selectUserQuery = `
SELECT *
FROM users
WHERE id = $1
LIMIT 1
`Complete Query Example
This example returns one user by ID.
package main
import (
"context"
"time"
"github.com/netlifeguru/db"
)
type User struct {
ID int64 `db:"id"`
Name string `db:"name"`
Email string `db:"email"`
Active bool `db:"active"`
CreatedAt time.Time `db:"created_at"`
}
const selectUserQuery = `
SELECT *
FROM users
WHERE id = ?
LIMIT 1
`
func GetUser(ctx context.Context, conn db.Conn, id int64) (User, bool, error) {
return db.Get[User](ctx, conn, selectUserQuery, id)
}Complete Usage Example
This example connects to the database, loads one user, and handles the not-found case.
package main
import (
"context"
"fmt"
"log"
_ "github.com/go-sql-driver/mysql"
"github.com/joho/godotenv"
)
func main() {
err := godotenv.Load()
if err != nil {
log.Println(".env file not found, I'm using system env variables")
}
conn, err := connectDB()
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
user, found, err := GetUser(ctx, conn, 1)
if err != nil {
log.Fatal(err)
}
if !found {
log.Println("user not found")
return
}
fmt.Printf(
"ID: %d | Name: %s | Email: %s | Active: %t | Created: %s\n",
user.ID,
user.Name,
user.Email,
user.Active,
user.CreatedAt.Format("2006-01-02 15:04:05"),
)
}Not Found
db.Get does not return an error when no row is found.
Instead, it returns found = false.
user, found, err := db.Get[User](ctx, conn, selectUserQuery, id)
if err != nil {
return User{}, false, err
}
if !found {
return User{}, false, nil
}This makes db.Get convenient for optional lookups.
Too Many Rows
db.Get expects zero or one row.
If the query returns more than one row, it returns an error.
Use a unique condition or LIMIT 1 when only one row should be returned.
SELECT *
FROM users
WHERE id = ?
LIMIT 1Avoid LIMIT 1 when duplicate rows should be detected by the application.
Driver Placeholder Differences
The Go call stays the same across drivers.
user, found, err := db.Get[User](ctx, conn, selectUserQuery, id)Only the query placeholder syntax changes.
| Driver | Placeholder |
|---|---|
| MySQL | ? |
| Postgres | $1 |
| Scylla | ? |
Scylla Example
For Scylla, use a query table designed for the lookup.
const selectUserByEmailQuery = `
SELECT *
FROM users_by_email
WHERE email = ?
LIMIT 1
`
func GetUserByEmail(ctx context.Context, conn db.Conn, email string) (User, bool, error) {
return db.Get[User](ctx, conn, selectUserByEmailQuery, email)
}Related Helpers
Use db.List when the query can return multiple rows.
users, err := db.List[User](ctx, conn, selectUsersQuery, 10)Use db.Value when the query returns a single scalar value.
total, found, err := db.Value[int64](ctx, conn, countUsersQuery)Use db.Maps when the result shape is dynamic.
rows, err := db.Maps(ctx, conn, selectRowsQuery)Related Examples
Standalone examples are available in the examples repository: