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 Maps(v interface{}, excluded ...string) (map[string]interface{}, error)
- func MapsStrict(v interface{}, excluded ...string) (map[string]interface{}, 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 ( // ErrNotAPointer is returned when a non-pointer is received // when a pointer is expected. ErrNotAPointer = errors.New("not a pointer") // ErrNotAStructPointer is returned when a non-struct pointer // is received but a struct pointer was expected ErrNotAStructPointer = errors.New("not a struct pointer") // ErrNotASlicePointer is returned when receiving an argument // that is expected to be a slice pointer, but it is not ErrNotASlicePointer = errors.New("not a slice pointer") // ErrStructFieldMissing is returned when trying to scan a value // to a column which does not match a struct. This means that // the struct does not have a field that matches the column // specified. ErrStructFieldMissing = errors.New("struct field missing") )
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 // OnAutoCloseError can be used to log errors which are returned from rows.Close() // By default this is a NOOP function OnAutoCloseError = func(error) {} )
Functions ¶
func Columns ¶
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/ceebydith/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/ceebydith/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 ¶
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/ceebydith/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 MapsStrict ¶
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" "fmt" "math/rand" "os" "github.com/ceebydith/scan" _ "github.com/proullon/ramsql/driver" ) func mustDB(name string, queries ...string) *sql.DB { db, err := sql.Open("ramsql", name) if err != nil { panic(err) } for _, s := range queries { _, err = db.Exec(s) if err != nil { panic(err) } } return db } func exampleDB() *sql.DB { return mustDB(fmt.Sprintf("%d", rand.Uint64()), `CREATE TABLE person ( id INTEGER NOT NULL, name VARCHAR(120) );`, `INSERT INTO person (id, name) VALUES (1, 'brett', 1);`, `INSERT INTO person (id, name) VALUES (2, 'fred', 1);`, ) } func main() { db := exampleDB() defer db.Close() rows, err := db.Query("SELECT id,name FROM person 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) } err = json.NewEncoder(os.Stdout).Encode(&person) if err != nil { panic(err) } }
Output: {"ID":1,"Name":"brett"}
Example (Scalar) ¶
package main import ( "database/sql" "fmt" "math/rand" "github.com/ceebydith/scan" _ "github.com/proullon/ramsql/driver" ) func mustDB(name string, queries ...string) *sql.DB { db, err := sql.Open("ramsql", name) if err != nil { panic(err) } for _, s := range queries { _, err = db.Exec(s) if err != nil { panic(err) } } return db } func exampleDB() *sql.DB { return mustDB(fmt.Sprintf("%d", rand.Uint64()), `CREATE TABLE person ( id INTEGER NOT NULL, name VARCHAR(120) );`, `INSERT INTO person (id, name) VALUES (1, 'brett', 1);`, `INSERT INTO person (id, name) VALUES (2, 'fred', 1);`, ) } func main() { db := exampleDB() defer db.Close() rows, err := db.Query("SELECT name FROM person 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 ¶
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" "fmt" "math/rand" "os" "github.com/ceebydith/scan" _ "github.com/proullon/ramsql/driver" ) func mustDB(name string, queries ...string) *sql.DB { db, err := sql.Open("ramsql", name) if err != nil { panic(err) } for _, s := range queries { _, err = db.Exec(s) if err != nil { panic(err) } } return db } func exampleDB() *sql.DB { return mustDB(fmt.Sprintf("%d", rand.Uint64()), `CREATE TABLE person ( id INTEGER NOT NULL, name VARCHAR(120) );`, `INSERT INTO person (id, name) VALUES (1, 'brett', 1);`, `INSERT INTO person (id, name) VALUES (2, 'fred', 1);`, ) } func main() { db := exampleDB() defer db.Close() rows, err := db.Query("SELECT id,name FROM person 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" "fmt" "math/rand" "os" "github.com/ceebydith/scan" _ "github.com/proullon/ramsql/driver" ) func mustDB(name string, queries ...string) *sql.DB { db, err := sql.Open("ramsql", name) if err != nil { panic(err) } for _, s := range queries { _, err = db.Exec(s) if err != nil { panic(err) } } return db } func exampleDB() *sql.DB { return mustDB(fmt.Sprintf("%d", rand.Uint64()), `CREATE TABLE person ( id INTEGER NOT NULL, name VARCHAR(120) );`, `INSERT INTO person (id, name) VALUES (1, 'brett', 1);`, `INSERT INTO person (id, name) VALUES (2, 'fred', 1);`, ) } func main() { db := exampleDB() defer db.Close() rows, err := db.Query("SELECT id,name FROM person ORDER BY id ASC") 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" "fmt" "math/rand" "os" "github.com/ceebydith/scan" _ "github.com/proullon/ramsql/driver" ) func mustDB(name string, queries ...string) *sql.DB { db, err := sql.Open("ramsql", name) if err != nil { panic(err) } for _, s := range queries { _, err = db.Exec(s) if err != nil { panic(err) } } return db } func exampleDB() *sql.DB { return mustDB(fmt.Sprintf("%d", rand.Uint64()), `CREATE TABLE person ( id INTEGER NOT NULL, name VARCHAR(120) );`, `INSERT INTO person (id, name) VALUES (1, 'brett', 1);`, `INSERT INTO person (id, name) VALUES (2, 'fred', 1);`, ) } func main() { db := exampleDB() defer db.Close() rows, err := db.Query("SELECT name FROM person ORDER BY id ASC") 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 ¶
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" "fmt" "math/rand" "os" "github.com/ceebydith/scan" _ "github.com/proullon/ramsql/driver" ) func mustDB(name string, queries ...string) *sql.DB { db, err := sql.Open("ramsql", name) if err != nil { panic(err) } for _, s := range queries { _, err = db.Exec(s) if err != nil { panic(err) } } return db } func exampleDB() *sql.DB { return mustDB(fmt.Sprintf("%d", rand.Uint64()), `CREATE TABLE person ( id INTEGER NOT NULL, name VARCHAR(120) );`, `INSERT INTO person (id, name) VALUES (1, 'brett', 1);`, `INSERT INTO person (id, name) VALUES (2, 'fred', 1);`, ) } func main() { db := exampleDB() defer db.Close() rows, err := db.Query("SELECT id,name FROM person ORDER BY id ASC") 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 ¶
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/ceebydith/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]