Skip to content

Instantly share code, notes, and snippets.

@kamichidu
Created January 17, 2017 03:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kamichidu/ae868884520234ab0a637ec56cc5a4ff to your computer and use it in GitHub Desktop.
Save kamichidu/ae868884520234ab0a637ec56cc5a4ff to your computer and use it in GitHub Desktop.
POC: golang database/sql, row to map[string]interface{} mapping
package main
import (
"database/sql"
"database/sql/driver"
"fmt"
"strings"
)
type Mapper interface {
sql.Scanner
}
type MetaHolder struct {
Values map[string]interface{}
}
type MapMapper struct {
Value map[string]interface{}
}
func (self *MapMapper) Scan(src interface{}) error {
if holder, ok := src.(*MetaHolder); ok {
self.Value = holder.Values
return nil
} else {
return fmt.Errorf("Scan error, unsupported %#v", src)
}
}
type delegator struct {
}
func (self *delegator) Open(name string) (driver.Conn, error) {
sects := strings.SplitN(name, ":", 2)
db, err := sql.Open(sects[0], sects[1])
if err != nil {
return nil, err
}
defer db.Close()
conn, err := db.Driver().Open(sects[1])
if err != nil {
return conn, err
}
return &dconn{delegate: conn}, nil
}
type dconn struct {
delegate driver.Conn
}
func (self *dconn) Begin() (driver.Tx, error) {
return self.delegate.Begin()
}
func (self *dconn) Close() error {
return self.delegate.Close()
}
func (self *dconn) Prepare(query string) (driver.Stmt, error) {
stmt, err := self.delegate.Prepare(query)
if err != nil {
return stmt, err
}
return &dstmt{delegate: stmt}, nil
}
type dstmt struct {
delegate driver.Stmt
}
func (self *dstmt) Exec(args []driver.Value) (driver.Result, error) {
return self.delegate.Exec(args)
}
func (self *dstmt) Query(args []driver.Value) (driver.Rows, error) {
rows, err := self.delegate.Query(args)
if err != nil {
return rows, err
}
return &drows{delegate: rows}, nil
}
func (self *dstmt) NumInput() int {
return self.delegate.NumInput()
}
func (self *dstmt) Close() error {
return self.delegate.Close()
}
type drows struct {
delegate driver.Rows
}
func (self *drows) Columns() []string {
return []string{""}
}
func (self *drows) Next(dest []driver.Value) error {
columns := self.delegate.Columns()
values := make([]driver.Value, len(columns))
err := self.delegate.Next(values)
if err != nil {
return err
}
holder := &MetaHolder{
Values: make(map[string]interface{}),
}
for i, column := range columns {
holder.Values[column] = values[i]
}
dest[0] = holder
return nil
}
func (self *drows) Close() error {
return self.delegate.Close()
}
func init() {
sql.Register("poc", &delegator{})
}
package main
import (
"database/sql"
"log"
"os"
"time"
_ "github.com/lib/pq"
)
func exec() int {
db, err := sql.Open("poc", "postgres:user=postgres password=postgres dbname=golang sslmode=disable")
if err != nil {
log.Printf("Failed to open database: %s\n", err)
return 1
}
defer db.Close()
started := time.Now()
row := new(MapMapper)
err = db.QueryRow("select * from information_schema.tables").Scan(row)
if err != nil {
log.Printf("Failed to query: %s\n", err)
return 1
}
ended := time.Now()
log.Printf("%#v\n", row.Value)
log.Printf("time required: %s\n", ended.Sub(started).String())
return 0
}
func main() {
os.Exit(exec())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment