Columbus is a SQL row mapper that converts rows to a map[string]any
- saving the need to scan rows into structs and then marshalling those structs as JSON.
Whilst Colombus is primarily focused on reading database rows directly as JSON - it also provides the ability to map rows to structs - without the need to create tedious matching .Scan()
args.
To install columbus, use go get:
go get github.com/go-andiamo/columbus
To update columbus to the latest version, run:
go get -u github.com/go-andiamo/columbus
Basic example to map all columns from any table
package main
import (
"context"
"database/sql"
"github.com/go-andiamo/columbus"
)
func ReadRows(ctx context.Context, db *sql.DB, tableName string) ([]map[string]any, error) {
return columbus.MustNewMapper("*", columbus.Query("FROM "+tableName)).
Rows(ctx, db, nil)
}
Re-using the same mapper to read all rows or a specific row
package main
import (
"context"
"database/sql"
"github.com/go-andiamo/columbus"
)
var mapper = columbus.MustNewMapper("*", columbus.Query(`FROM people`))
func ReadAll(ctx context.Context, db *sql.DB) ([]map[string]any, error) {
return mapper.Rows(ctx, db, nil)
}
func ReadById(ctx context.Context, db *sql.DB, id any) (map[string]any, error) {
return mapper.ExactlyOneRow(ctx, db, []any{id}, columbus.AddClause(`WHERE id = ?`))
}
Using mappings to add a property
package main
import (
"context"
"database/sql"
"github.com/go-andiamo/columbus"
"strings"
)
func ReadRowsWithInitials(ctx context.Context, db *sql.DB) ([]map[string]any, error) {
return columbus.MustNewMapper("given_name,family_name",
columbus.Mappings{
"family_name": {PostProcess: func(ctx context.Context, sqli columbus.SqlInterface, row map[string]any, value any) (bool, any, error) {
givenName := row["given_name"].(string)
familyName := row["family_name"].(string)
row["initials"] = strings.ToUpper(givenName[:1] + "." + familyName[:1] + ".")
return false, nil, nil
}},
},
columbus.Query("FROM people")).Rows(ctx, db, nil)
}
Using row post processor to add a property
package main
import (
"context"
"database/sql"
"github.com/go-andiamo/columbus"
"strings"
)
func ReadRowsWithInitials(ctx context.Context, db *sql.DB) ([]map[string]any, error) {
return columbus.MustNewMapper("given_name,family_name",
columbus.RowPostProcessorFunc(func(ctx context.Context, sqli columbus.SqlInterface, row map[string]any) error {
givenName := row["given_name"].(string)
familyName := row["family_name"].(string)
row["initials"] = strings.ToUpper(givenName[:1] + "." + familyName[:1] + ".")
return nil
}),
columbus.Query("FROM people")).Rows(ctx, db, nil)
}
Struct mapping
package main
import (
"context"
"database/sql"
"github.com/go-andiamo/columbus"
)
type Person struct {
FamilyName string `sql:"family_name"`
GivenName string `sql:"given_name"`
}
var PersonMapper = columbus.MustNewStructMapper[Person]("given_name,family_name", columbus.Query("FROM people"))
func GetPeople(ctx context.Context, db *sql.DB, args ...any) ([]Person, error) {
return PersonMapper.Rows(ctx, db, args)
}