Categorygithub.com/yongPhone/sqlx
modulepackage
1.2.1
Repository: https://github.com/yongphone/sqlx.git
Documentation: pkg.go.dev

# README

sqlx

Build Status Coverage Status Godoc license

sqlx is a library which provides a set of extensions on go's standard database/sql library. The sqlx versions of sql.DB, sql.TX, sql.Stmt, et al. all leave the underlying interfaces untouched, so that their interfaces are a superset on the standard ones. This makes it relatively painless to integrate existing codebases using database/sql with sqlx.

Major additional concepts are:

  • Marshal rows into structs (with embedded struct support), maps, and slices
  • Named parameter support including prepared statements
  • Get and Select to go quickly from query to struct/slice

In addition to the godoc API documentation, there is also some user documentation that explains how to use database/sql along with sqlx.

Recent Changes

  • support logger (the default logger is logrus, and you can custom the logger by sqlx.SetLogger(myLogger))

  • The introduction of sql.ColumnType sets the required minimum Go version to 1.8.

  • sqlx/types.JsonText has been renamed to JSONText to follow Go naming conventions.

This breaks backwards compatibility, but it's in a way that is trivially fixable (s/JsonText/JSONText/g). The types package is both experimental and not in active development currently.

  • Using Go 1.6 and below with types.JSONText and types.GzippedText can be potentially unsafe, especially when used with common auto-scan sqlx idioms like Select and Get. See golang bug #13905.

Backwards Compatibility

There is no Go1-like promise of absolute stability, but I take the issue seriously and will maintain the library in a compatible state unless vital bugs prevent me from doing so. Since #59 and #60 necessitated breaking behavior, a wider API cleanup was done at the time of fixing. It's possible this will happen in future; if it does, a git tag will be provided for users requiring the old behavior to continue to use it until such a time as they can migrate.

install

go get github.com/jmoiron/sqlx

issues

Row headers can be ambiguous (SELECT 1 AS a, 2 AS a), and the result of Columns() does not fully qualify column names in queries like:

SELECT a.id, a.name, b.id, b.name FROM foos AS a JOIN foos AS b ON a.parent = b.id;

making a struct or map destination ambiguous. Use AS in your queries to give columns distinct names, rows.Scan to scan them manually, or SliceScan to get a slice of results.

usage

Below is an example which shows some common use cases for sqlx. Check sqlx_test.go for more usage.

package main

import (
    "database/sql"
    "fmt"
    "log"
    
    _ "github.com/lib/pq"
    "github.com/jmoiron/sqlx"
)

var schema = `
CREATE TABLE person (
    first_name text,
    last_name text,
    email text
);

CREATE TABLE place (
    country text,
    city text NULL,
    telcode integer
)`

type Person struct {
    FirstName string `db:"first_name"`
    LastName  string `db:"last_name"`
    Email     string
}

type Place struct {
    Country string
    City    sql.NullString
    TelCode int
}

func main() {
    // this Pings the database trying to connect, panics on error
    // use sqlx.Open() for sql.Open() semantics
    db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
    if err != nil {
        log.Fatalln(err)
    }

    // exec the schema or fail; multi-statement Exec behavior varies between
    // database drivers;  pq will exec them all, sqlite3 won't, ymmv
    db.MustExec(schema)
    
    tx := db.MustBegin()
    tx.MustExec("INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "Jason", "Moiron", "[email protected]")
    tx.MustExec("INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "John", "Doe", "[email protected]")
    tx.MustExec("INSERT INTO place (country, city, telcode) VALUES ($1, $2, $3)", "United States", "New York", "1")
    tx.MustExec("INSERT INTO place (country, telcode) VALUES ($1, $2)", "Hong Kong", "852")
    tx.MustExec("INSERT INTO place (country, telcode) VALUES ($1, $2)", "Singapore", "65")
    // Named queries can use structs, so if you have an existing struct (i.e. person := &Person{}) that you have populated, you can pass it in as &person
    tx.NamedExec("INSERT INTO person (first_name, last_name, email) VALUES (:first_name, :last_name, :email)", &Person{"Jane", "Citizen", "[email protected]"})
    tx.Commit()

    // Query the database, storing results in a []Person (wrapped in []interface{})
    people := []Person{}
    db.Select(&people, "SELECT * FROM person ORDER BY first_name ASC")
    jason, john := people[0], people[1]

    fmt.Printf("%#v\n%#v", jason, john)
    // Person{FirstName:"Jason", LastName:"Moiron", Email:"[email protected]"}
    // Person{FirstName:"John", LastName:"Doe", Email:"[email protected]"}

    // You can also get a single result, a la QueryRow
    jason = Person{}
    err = db.Get(&jason, "SELECT * FROM person WHERE first_name=$1", "Jason")
    fmt.Printf("%#v\n", jason)
    // Person{FirstName:"Jason", LastName:"Moiron", Email:"[email protected]"}

    // if you have null fields and use SELECT *, you must use sql.Null* in your struct
    places := []Place{}
    err = db.Select(&places, "SELECT * FROM place ORDER BY telcode ASC")
    if err != nil {
        fmt.Println(err)
        return
    }
    usa, singsing, honkers := places[0], places[1], places[2]
    
    fmt.Printf("%#v\n%#v\n%#v\n", usa, singsing, honkers)
    // Place{Country:"United States", City:sql.NullString{String:"New York", Valid:true}, TelCode:1}
    // Place{Country:"Singapore", City:sql.NullString{String:"", Valid:false}, TelCode:65}
    // Place{Country:"Hong Kong", City:sql.NullString{String:"", Valid:false}, TelCode:852}

    // Loop through rows using only one struct
    place := Place{}
    rows, err := db.Queryx("SELECT * FROM place")
    for rows.Next() {
        err := rows.StructScan(&place)
        if err != nil {
            log.Fatalln(err)
        } 
        fmt.Printf("%#v\n", place)
    }
    // Place{Country:"United States", City:sql.NullString{String:"New York", Valid:true}, TelCode:1}
    // Place{Country:"Hong Kong", City:sql.NullString{String:"", Valid:false}, TelCode:852}
    // Place{Country:"Singapore", City:sql.NullString{String:"", Valid:false}, TelCode:65}

    // Named queries, using `:name` as the bindvar.  Automatic bindvar support
    // which takes into account the dbtype based on the driverName on sqlx.Open/Connect
    _, err = db.NamedExec(`INSERT INTO person (first_name,last_name,email) VALUES (:first,:last,:email)`, 
        map[string]interface{}{
            "first": "Bin",
            "last": "Smuth",
            "email": "[email protected]",
    })

    // Selects Mr. Smith from the database
    rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:fn`, map[string]interface{}{"fn": "Bin"})

    // Named queries can also use structs.  Their bind names follow the same rules
    // as the name -> db mapping, so struct fields are lowercased and the `db` tag
    // is taken into consideration.
    rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:first_name`, jason)
}

# Packages

Package reflectx implements extensions to the standard reflect lib suitable for implementing marshalling and unmarshalling packages.
No description provided by the author

# Functions

BindNamed binds a struct or a map to a query with named parameters.
BindType returns the bindtype for a given database given a drivername.
Connect to a database and verify with a ping.
ConnectContext to a database and verify with a ping.
Get does a QueryRow using the provided Queryer, and scans the resulting row to dest.
GetContext does a QueryRow using the provided Queryer, and scans the resulting row to dest.
In expands slice values in args, returning the modified query string and a new arg list that can be executed by a database.
LoadFile exec's every statement in a file (as a single call to Exec).
LoadFileContext exec's every statement in a file (as a single call to Exec).
MapScan scans a single Row into the dest map[string]interface{}.
MustConnect connects to a database and panics on error.
MustExec execs the query using e and panics if there was an error.
MustExecContext execs the query using e and panics if there was an error.
MustOpen is the same as sql.Open, but returns an *sqlx.DB instead and panics on error.
Named takes a query using named parameters and an argument and returns a new query with a list of args that can be executed by a database.
NamedExec uses BindStruct to get a query executable by the driver and then runs Exec on the result.
NamedExecContext uses BindStruct to get a query executable by the driver and then runs Exec on the result.
NamedQuery binds a named query and then runs Query on the result using the provided Ext (sqlx.Tx, sqlx.Db).
NamedQueryContext binds a named query and then runs Query on the result using the provided Ext (sqlx.Tx, sqlx.Db).
NewDb returns a new sqlx DB wrapper for a pre-existing *sql.DB.
Open is the same as sql.Open, but returns an *sqlx.DB instead.
Preparex prepares a statement.
PreparexContext prepares a statement.
Rebind a query from the default bindtype (QUESTION) to the target bindtype.
Select executes a query using the provided Queryer, and StructScans each row into dest, which must be a slice.
SelectContext executes a query using the provided Queryer, and StructScans each row into dest, which must be a slice.
No description provided by the author
SliceScan a row, returning a []interface{} with values similar to MapScan.
StructScan all rows from an sql.Rows or an sqlx.Rows into the dest slice.

# Constants

Bindvar types supported by Rebind, BindMap and BindStruct.
Bindvar types supported by Rebind, BindMap and BindStruct.
Bindvar types supported by Rebind, BindMap and BindStruct.
Bindvar types supported by Rebind, BindMap and BindStruct.
Bindvar types supported by Rebind, BindMap and BindStruct.

# Variables

NameMapper is used to map column names to struct field names.

# Structs

Conn is a wrapper around sql.Conn with extra functionality.
DB is a wrapper around sql.DB which keeps track of the driverName upon Open, used mostly to automatically bind named queries using the right bindvars.
No description provided by the author
NamedStmt is a prepared statement that executes named queries.
Row is a reimplementation of sql.Row in order to gain access to the underlying sql.Rows.Columns() data, necessary for StructScan.
Rows is a wrapper around sql.Rows which caches costly reflect operations during a looped StructScan.
Stmt is an sqlx wrapper around sql.Stmt with extra functionality.
Tx is an sqlx wrapper around sql.Tx with extra functionality.

# Interfaces

ColScanner is an interface used by MapScan and SliceScan.
Execer is an interface used by MustExec and LoadFile.
ExecerContext is an interface used by MustExecContext and LoadFileContext.
Ext is a union interface which can bind, query, and exec, used by NamedQuery and NamedExec.
ExtContext is a union interface which can bind, query, and exec, with Context used by NamedQueryContext and NamedExecContext.
Preparer is an interface used by Preparex.
PreparerContext is an interface used by PreparexContext.
Queryer is an interface used by Get and Select.
QueryerContext is an interface used by GetContext and SelectContext.