package main
import (
"database/sql"
"errors"
"fmt"
"reflect"
)
var sqlDB *sql.DB
type Flower struct {
Color string
Size int
Weight int
}
type T struct{}
var FlowerByColor = Select(" * FROM tablex WHERE Color=$ LIMIT 1", reflect.TypeOf(Flower{}))
func main() {
// Select a flower based on its color from database
// invalid resource type; resource of type Flower is expected
// I would like this to not compile as I pass an invalid resource type T instead of type Flower
var color string
if err := FlowerByColor(T{}, &color); err != nil {
fmt.Printf("err %v\n", err)
}
// invalid param; type string (Folower.Color) type is expected
var colorInvalid int
// I would like this to not compile as I pass an invalid color type
if err := FlowerByColor(Flower{}, colorInvalid); err != nil {
fmt.Printf("err %v\n", err)
}
// correct query
color = "red"
if err := FlowerByColor(Flower{}, color); err != nil {
fmt.Printf("err %v\n", err)
}
// Note: a proper SelectFunc would actually accept only pointers to Flower so that
// it can unmarshal data into the resource as below. For brevity I omitted handling
// pointers in SelectFunc
resource := new(Flower)
if err := FlowerByColor(resource, color); err != nil {
fmt.Printf("err %v\n", err)
}
// so something with the data from realVal
fmt.Printf("our flower of color %v has a size of %v", color, realVal.Size)
}
// SelectFunc receives a resource and the query params
type SelectFunc func(resource interface{}, params ...interface{}) error
// select receives a sql query and the type that represents
//the sql table from database.
// Returns a function that executes the sql query with the matching params from tv.
func Select(q string, tv reflect.Type) SelectFunc {
paramTypes, err := parseQuery(q, tv)
if err != nil {
panic("invalid query")
}
return func(resource interface{}, param ...interface{}) error {
// validate input
// resource must match the resource type
if reflect.TypeOf(resource) != tv {
return errors.New("invalid resource type")