ScanStructSlice
Use ScanStructSlice to load database rows into a typed Go slice.
Use ScanStructSlice when you want to scan all database rows into a typed Go slice.
This is the simplest mapper function for list queries.
It is useful when you expect zero or more rows and want the result as []T.
When to Use It
Use ScanStructSlice when:
- you are building a list query
- you want all rows returned as a slice
- the result set can safely fit in memory
- you do not need custom per-row callback logic
- the caller expects
[]T
For callback-based row processing, use ScanStructRows.
Define a Struct
Create a struct that represents one row from the query result.
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"`
}The db tags tell mapper which database columns should be assigned to each field.
Query Rows
Query rows using your database driver.
rows, err := db.Query(`
SELECT *
FROM users
ORDER BY created_at DESC
`)
if err != nil {
return nil, err
}
defer rows.Close()Scan Into a Slice
Pass the rows into ScanStructSlice.
return mapper.ScanStructSlice[User](rows)Mapper scans every row into a User value and returns a []User.
Complete Query Example
package main
import (
"database/sql"
"time"
"github.com/netlifeguru/mapper"
)
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"`
}
func getUsers(db *sql.DB) ([]User, error) {
rows, err := db.Query(`
SELECT *
FROM users
ORDER BY created_at DESC
`)
if err != nil {
return nil, err
}
defer rows.Close()
return mapper.ScanStructSlice[User](rows)
}Complete Usage Example
package main
import (
"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")
}
db, err := connectDB()
if err != nil {
log.Fatal(err)
}
defer db.Close()
users, err := getUsers(db)
if err != nil {
log.Fatal(err)
}
for _, user := range users {
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"),
)
}
}The connectDB function is part of the standalone example and is responsible for opening the MySQL database connection.
Empty Result
When the query returns no rows, ScanStructSlice returns an empty slice.
users, err := mapper.ScanStructSlice[User](rows)
if err != nil {
return nil, err
}
fmt.Println(len(users)) // 0This is useful for API list responses where an empty result is valid.
Difference From ScanStructRows
ScanStructSlice automatically builds the slice for you.
users, err := mapper.ScanStructSlice[User](rows)With ScanStructRows, you control what happens for every scanned row.
var users []User
err = mapper.ScanStructRows[User](rows, func(user *User) error {
users = append(users, *user)
return nil
})Both approaches are valid.
Use ScanStructSlice for simple list queries.
Use ScanStructRows when you need callback control.
Rows Are Consumed
Rows are consumed during scanning.
Do not scan the same rows value twice.
users, err := mapper.ScanStructSlice[User](rows)
if err != nil {
return nil, err
}
// Do not scan the same rows again.
// Run the query again if you need another scan.Related Example
A standalone example is available in the examples repository: