Documentation ¶
Overview ¶
Package scan provides functionality for scanning database/sql rows into slices, structs, and primitive types dynamically
Index ¶
- Variables
- func Columns(v interface{}, excluded ...string) ([]string, error)
- func ColumnsStrict(v interface{}, excluded ...string) ([]string, error)
- func Row(v interface{}, r RowsScanner) error
- func RowStrict(v interface{}, r RowsScanner) error
- func Rows(v interface{}, r RowsScanner) (outerr error)
- func RowsStrict(v interface{}, r RowsScanner) (outerr error)
- func Values(cols []string, v interface{}) ([]interface{}, error)
- type RowsScanner
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrTooManyColumns indicates that a select query returned multiple columns and // attempted to bind to a slice of a primitive type. For example, trying to bind // `select col1, col2 from mutable` to []string ErrTooManyColumns = errors.New("too many columns returned for primitive slice") // ErrSliceForRow occurs when trying to use Row on a slice ErrSliceForRow = errors.New("cannot scan Row into slice") // AutoClose is true when scan should automatically close Scanner when the scan // is complete. If you set it to false, then you must defer rows.Close() manually AutoClose = true )
Functions ¶
func Columns ¶ added in v1.1.0
Columns scans a struct and returns a list of strings that represent the assumed column names based on the db struct tag, or the field name. Any field or struct tag that matches a string within the excluded list will be excluded from the result
Example ¶
package main import ( "fmt" "github.com/blockloop/scan" ) func main() { var person struct { ID int `db:"person_id"` Name string } cols, _ := scan.Columns(&person) fmt.Printf("%+v", cols) }
Output: [person_id Name]
Example (Exclude) ¶
package main import ( "fmt" "github.com/blockloop/scan" ) func main() { var person struct { ID int `db:"id"` Name string `db:"name"` Age string `db:"-"` } cols, _ := scan.Columns(&person) fmt.Printf("%+v", cols) }
Output: [id name]
func ColumnsStrict ¶ added in v1.1.0
ColumnsStrict is identical to Columns, but it only searches struct tags and excludes fields not tagged with the db struct tag
Example ¶
package main import ( "fmt" "github.com/blockloop/scan" ) func main() { var person struct { ID int `db:"id"` Name string Age string `db:"age"` } cols, _ := scan.ColumnsStrict(&person) fmt.Printf("%+v", cols) }
Output: [id age]
func Row ¶
func Row(v interface{}, r RowsScanner) error
Row scans a single row into a single variable. It requires that you use db.Query and not db.QueryRow, because QueryRow does not return column names. There is no performance impact in using one over the other. QueryRow only defers returning err until Scan is called, which is an unnecessary optimization for this library.
Example ¶
package main import ( "database/sql" "encoding/json" "os" "testing" "github.com/blockloop/scan" _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/require" ) func mustDB(t testing.TB, schema string) *sql.DB { db, err := sql.Open("sqlite3", ":memory:") require.NoError(t, err) _, err = db.Exec(schema) require.NoError(t, err) return db } func exampleDB() *sql.DB { return mustDB(&testing.T{}, `CREATE TABLE persons ( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(120) NOT NULL DEFAULT '' ); INSERT INTO PERSONS (name) VALUES ('brett'), ('fred');`) } func main() { db := exampleDB() rows, err := db.Query("SELECT id,name FROM persons LIMIT 1") if err != nil { panic(err) } var person struct { ID int `db:"id"` Name string `db:"name"` } err = scan.Row(&person, rows) if err != nil { panic(err) } json.NewEncoder(os.Stdout).Encode(&person) }
Output: {"ID":1,"Name":"brett"}
Example (Scalar) ¶
package main import ( "database/sql" "fmt" "testing" "github.com/blockloop/scan" _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/require" ) func mustDB(t testing.TB, schema string) *sql.DB { db, err := sql.Open("sqlite3", ":memory:") require.NoError(t, err) _, err = db.Exec(schema) require.NoError(t, err) return db } func exampleDB() *sql.DB { return mustDB(&testing.T{}, `CREATE TABLE persons ( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(120) NOT NULL DEFAULT '' ); INSERT INTO PERSONS (name) VALUES ('brett'), ('fred');`) } func main() { db := exampleDB() rows, err := db.Query("SELECT name FROM persons LIMIT 1") if err != nil { panic(err) } var name string err = scan.Row(&name, rows) if err != nil { panic(err) } fmt.Printf("%q", name) }
Output: "brett"
func RowStrict ¶ added in v1.3.0
func RowStrict(v interface{}, r RowsScanner) error
RowStrict scans a single row into a single variable. It is identical to Row, but it ignores fields that do not have a db tag
Example ¶
package main import ( "database/sql" "encoding/json" "os" "testing" "github.com/blockloop/scan" _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/require" ) func mustDB(t testing.TB, schema string) *sql.DB { db, err := sql.Open("sqlite3", ":memory:") require.NoError(t, err) _, err = db.Exec(schema) require.NoError(t, err) return db } func exampleDB() *sql.DB { return mustDB(&testing.T{}, `CREATE TABLE persons ( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(120) NOT NULL DEFAULT '' ); INSERT INTO PERSONS (name) VALUES ('brett'), ('fred');`) } func main() { db := exampleDB() rows, err := db.Query("SELECT id,name FROM persons LIMIT 1") if err != nil { panic(err) } var person struct { ID int Name string `db:"name"` } err = scan.RowStrict(&person, rows) if err != nil { panic(err) } json.NewEncoder(os.Stdout).Encode(&person) }
Output: {"ID":0,"Name":"brett"}
func Rows ¶
func Rows(v interface{}, r RowsScanner) (outerr error)
Rows scans sql rows into a slice (v)
Example ¶
package main import ( "database/sql" "encoding/json" "os" "testing" "github.com/blockloop/scan" _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/require" ) func mustDB(t testing.TB, schema string) *sql.DB { db, err := sql.Open("sqlite3", ":memory:") require.NoError(t, err) _, err = db.Exec(schema) require.NoError(t, err) return db } func exampleDB() *sql.DB { return mustDB(&testing.T{}, `CREATE TABLE persons ( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(120) NOT NULL DEFAULT '' ); INSERT INTO PERSONS (name) VALUES ('brett'), ('fred');`) } func main() { db := exampleDB() rows, err := db.Query("SELECT id,name FROM persons ORDER BY name") if err != nil { panic(err) } var persons []struct { ID int `db:"id"` Name string `db:"name"` } err = scan.Rows(&persons, rows) if err != nil { panic(err) } json.NewEncoder(os.Stdout).Encode(&persons) }
Output: [{"ID":1,"Name":"brett"},{"ID":2,"Name":"fred"}]
Example (Primitive) ¶
package main import ( "database/sql" "encoding/json" "os" "testing" "github.com/blockloop/scan" _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/require" ) func mustDB(t testing.TB, schema string) *sql.DB { db, err := sql.Open("sqlite3", ":memory:") require.NoError(t, err) _, err = db.Exec(schema) require.NoError(t, err) return db } func exampleDB() *sql.DB { return mustDB(&testing.T{}, `CREATE TABLE persons ( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(120) NOT NULL DEFAULT '' ); INSERT INTO PERSONS (name) VALUES ('brett'), ('fred');`) } func main() { db := exampleDB() rows, err := db.Query("SELECT name FROM persons ORDER BY name") if err != nil { panic(err) } var names []string err = scan.Rows(&names, rows) if err != nil { panic(err) } json.NewEncoder(os.Stdout).Encode(&names) }
Output: ["brett","fred"]
func RowsStrict ¶ added in v1.3.0
func RowsStrict(v interface{}, r RowsScanner) (outerr error)
RowsStrict scans sql rows into a slice (v) only using db tags
Example ¶
package main import ( "database/sql" "encoding/json" "os" "testing" "github.com/blockloop/scan" _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/require" ) func mustDB(t testing.TB, schema string) *sql.DB { db, err := sql.Open("sqlite3", ":memory:") require.NoError(t, err) _, err = db.Exec(schema) require.NoError(t, err) return db } func exampleDB() *sql.DB { return mustDB(&testing.T{}, `CREATE TABLE persons ( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(120) NOT NULL DEFAULT '' ); INSERT INTO PERSONS (name) VALUES ('brett'), ('fred');`) } func main() { db := exampleDB() rows, err := db.Query("SELECT id,name FROM persons ORDER BY name") if err != nil { panic(err) } var persons []struct { ID int Name string `db:"name"` } err = scan.Rows(&persons, rows) if err != nil { panic(err) } json.NewEncoder(os.Stdout).Encode(&persons) }
Output: [{"ID":0,"Name":"brett"},{"ID":0,"Name":"fred"}]
func Values ¶ added in v1.2.0
Values scans a struct and returns the values associated with the columns provided. Only simple value types are supported (i.e. Bool, Ints, Uints, Floats, Interface, String)
Example ¶
package main import ( "fmt" "github.com/blockloop/scan" ) func main() { person := struct { ID int `db:"id"` Name string `db:"name"` }{ ID: 1, Name: "Brett", } cols := []string{"id", "name"} vals, _ := scan.Values(cols, &person) fmt.Printf("%+v", vals) }
Output: [1 Brett]