Documentation ¶
Overview ¶
Package gopkg.in/pg.v3 implements a PostgreSQL client.
Example (ComplexQuery) ¶
package main import ( "fmt" "gopkg.in/pg.v3" ) type ArticleFilter struct { Id int64 Name string CategoryId int } func (f *ArticleFilter) NameFilter() pg.Q { if f.Name == "" { return "" } return pg.MustFormatQ("name = ?", f.Name) } func (f *ArticleFilter) CategoryFilter() pg.Q { if f.CategoryId == 0 { return "" } return pg.MustFormatQ("category_id = ?", f.CategoryId) } func (f *ArticleFilter) Filters() pg.Q { return pg.Where(f.NameFilter(), f.CategoryFilter()) } type Article struct { Id int64 `pg:",nullempty"` Name string CategoryId int } func CreateArticle(db *pg.DB, article *Article) error { model := pg.NewModel(article, "") _, err := db.QueryOne(model, ` INSERT INTO articles (?Fields) VALUES (?Values) RETURNING id `, model) return err } func GetArticle(db *pg.DB, id int64) (*Article, error) { var article Article _, err := db.QueryOne(&article, `SELECT * FROM articles WHERE id = ?`, id) return &article, err } func GetArticles(db *pg.DB, f *ArticleFilter) ([]Article, error) { var articles []Article _, err := db.Query(&articles, ` SELECT * FROM articles WHERE ?Filters `, f) return articles, err } func main() { db := pg.Connect(&pg.Options{ User: "postgres", }) defer db.Close() _, err := db.Exec(`CREATE TEMP TABLE articles (id serial, name text, category_id int)`) if err != nil { panic(err) } err = CreateArticle(db, &Article{Name: "article1", CategoryId: 1}) if err != nil { panic(err) } err = CreateArticle(db, &Article{Name: "article2", CategoryId: 2}) if err != nil { panic(err) } articles, err := GetArticles(db, &ArticleFilter{}) if err != nil { panic(err) } fmt.Printf("%d %v %v\n", len(articles), articles[0], articles[1]) articles, err = GetArticles(db, &ArticleFilter{CategoryId: 1}) if err != nil { panic(err) } fmt.Printf("%d %v\n", len(articles), articles[0]) }
Output: 2 {1 article1 1} {2 article2 2} 1 {1 article1 1}
Example (Json) ¶
package main import ( "database/sql/driver" "encoding/json" "fmt" "gopkg.in/pg.v3" ) type jsonMap map[string]interface{} func (m *jsonMap) Scan(value interface{}) error { return json.Unmarshal(value.([]byte), m) } func (m jsonMap) Value() (driver.Value, error) { b, err := json.Marshal(m) if err != nil { return nil, err } return string(b), nil } type Item struct { Id int64 Data jsonMap } func CreateItem(db *pg.DB, item *Item) error { _, err := db.ExecOne(`INSERT INTO items VALUES (?id, ?data)`, item) return err } func GetItem(db *pg.DB, id int64) (*Item, error) { var item Item _, err := db.QueryOne(&item, ` SELECT * FROM items WHERE id = ? `, id) return &item, err } func GetItems(db *pg.DB) ([]Item, error) { var items []Item _, err := db.Query(&items, ` SELECT * FROM items `) return items, err } func main() { db := pg.Connect(&pg.Options{ User: "postgres", }) defer db.Close() _, err := db.Exec(`CREATE TEMP TABLE items (id serial, data json)`) if err != nil { panic(err) } item := &Item{ Id: 1, Data: jsonMap{"hello": "world"}, } if err := CreateItem(db, item); err != nil { panic(err) } item, err = GetItem(db, 1) if err != nil { panic(err) } fmt.Println(item) }
Output: &{1 map[hello:world]}
Index ¶
- Variables
- func AppendQ(dst []byte, src string, params ...interface{}) ([]byte, error)
- func Decode(dst interface{}, b []byte) error
- func DecodeValue(v reflect.Value, b []byte) error
- type Collection
- type ColumnLoader
- type DB
- func (db *DB) Begin() (*Tx, error)
- func (db *DB) Close() error
- func (db *DB) CopyFrom(r io.Reader, q string, args ...interface{}) (Result, error)
- func (db *DB) CopyTo(w io.WriteCloser, q string, args ...interface{}) (Result, error)
- func (db *DB) Exec(q string, args ...interface{}) (res Result, err error)
- func (db *DB) ExecOne(q string, args ...interface{}) (Result, error)
- func (db *DB) Listen(channels ...string) (*Listener, error)
- func (db *DB) Prepare(q string) (*Stmt, error)
- func (db *DB) Query(coll interface{}, q string, args ...interface{}) (res Result, err error)
- func (db *DB) QueryOne(record interface{}, q string, args ...interface{}) (Result, error)
- func (db *DB) RunInTransaction(fn func(*Tx) error) error
- func (db *DB) WithTimeout(d time.Duration) *DB
- type Error
- type F
- type IntSet
- type IntegrityError
- type Ints
- type Listener
- type Model
- type Options
- type Q
- type QueryAppender
- type RawQueryAppender
- type Result
- type Stmt
- func (stmt *Stmt) Close() error
- func (stmt *Stmt) Exec(args ...interface{}) (res Result, err error)
- func (stmt *Stmt) ExecOne(args ...interface{}) (Result, error)
- func (stmt *Stmt) Query(coll interface{}, args ...interface{}) (res Result, err error)
- func (stmt *Stmt) QueryOne(record interface{}, args ...interface{}) (Result, error)
- type Strings
- type Tx
- func (tx *Tx) Commit() (err error)
- func (tx *Tx) Exec(q string, args ...interface{}) (Result, error)
- func (tx *Tx) ExecOne(q string, args ...interface{}) (Result, error)
- func (tx *Tx) Prepare(q string) (*Stmt, error)
- func (tx *Tx) Query(coll interface{}, q string, args ...interface{}) (Result, error)
- func (tx *Tx) QueryOne(record interface{}, q string, args ...interface{}) (Result, error)
- func (tx *Tx) Rollback() (err error)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrSSLNotSupported = errorf("pg: SSL is not enabled on the server") ErrNoRows = errorf("pg: no rows in result set") ErrMultiRows = errorf("pg: multiple rows in result set") )
var (
// Discard can be used with Query and QueryOne to discard rows.
Discard discardLoader
)
Functions ¶
Types ¶
type Collection ¶
type Collection interface { // NewRecord returns ColumnLoader or struct that are used to scan // columns from the current row. NewRecord() interface{} }
Collection is a set of records mapped to database rows.
type ColumnLoader ¶
type ColumnLoader interface { // Scan assigns a column value from a row. // // An error should be returned if the value can not be stored // without loss of information. // // TODO(vmihailenco): rename to ScanColumn LoadColumn(colIdx int, colName string, b []byte) error }
ColumnLoader is an interface used by LoadColumn.
TODO(vmihailenco): rename to ColumnScanner
func LoadInto ¶
func LoadInto(values ...interface{}) ColumnLoader
LoadInto returns ColumnLoader that copies the columns in the row into the values.
TODO(vmihailenco): rename to Scan
Example ¶
var s1, s2 string _, err := db.QueryOne(pg.LoadInto(&s1, &s2), `SELECT ?, ?`, "foo", "bar") fmt.Println(s1, s2, err)
Output: foo bar <nil>
func NewColumnLoader ¶
func NewColumnLoader(dst interface{}) (ColumnLoader, error)
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB is a database handle representing a pool of zero or more underlying connections. It's safe for concurrent use by multiple goroutines.
func Connect ¶
Connect connects to a database using provided options.
The returned DB is safe for concurrent use by multiple goroutines and maintains its own connection pool.
Example ¶
db := pg.Connect(&pg.Options{ User: "postgres", }) err := db.Close() fmt.Println(err)
Output: <nil>
func (*DB) Begin ¶
Example ¶
tx, err := db.Begin() if err != nil { panic(err) } _, err = tx.Exec(`CREATE TABLE tx_test()`) if err != nil { panic(err) } err = tx.Rollback() if err != nil { panic(err) } _, err = db.Exec(`SELECT * FROM tx_test`) fmt.Println(err)
Output: ERROR #42P01 relation "tx_test" does not exist:
func (*DB) Close ¶
Close closes the database client, releasing any open resources.
It is rare to Close a DB, as the DB handle is meant to be long-lived and shared between many goroutines.
func (*DB) CopyFrom ¶
CopyFrom copies data from reader to a table.
Example ¶
_, err := db.Exec(`CREATE TEMP TABLE words(word text, len int)`) if err != nil { panic(err) } r := strings.NewReader("hello,5\nfoo,3\n") _, err = db.CopyFrom(r, `COPY words FROM STDIN WITH CSV`) if err != nil { panic(err) } buf := &bytes.Buffer{} _, err = db.CopyTo(&NopWriteCloser{buf}, `COPY words TO STDOUT WITH CSV`) if err != nil { panic(err) } fmt.Println(buf.String())
Output: hello,5 foo,3
func (*DB) Exec ¶
Exec executes a query ignoring returned rows. The args are for any placeholder parameters in the query.
Example ¶
res, err := db.Exec(`CREATE TEMP TABLE test()`) fmt.Println(res.Affected(), err)
Output: -1 <nil>
func (*DB) ExecOne ¶
ExecOne acts like Exec, but query must affect only one row. It returns ErrNoRows error when query returns zero rows or ErrMultiRows when query returns multiple rows.
func (*DB) Prepare ¶
Prepare creates a prepared statement for later queries or executions. Multiple queries or executions may be run concurrently from the returned statement.
Example ¶
stmt, err := db.Prepare(`SELECT $1::text, $2::text`) if err != nil { panic(err) } var s1, s2 string _, err = stmt.QueryOne(pg.LoadInto(&s1, &s2), "foo", "bar") fmt.Println(s1, s2, err)
Output: foo bar <nil>
func (*DB) Query ¶
Query executes a query that returns rows, typically a SELECT. The args are for any placeholder parameters in the query.
Example ¶
package main import ( "fmt" "gopkg.in/pg.v3" ) type User struct { Id int64 `pg:",nullempty"` Name string Emails []string } func (u User) String() string { return fmt.Sprintf("User<%d %s %v>", u.Id, u.Name, u.Emails) } func CreateUser(db *pg.DB, user *User) error { model := pg.NewModel(user, "") _, err := db.QueryOne(model, ` INSERT INTO users (?Fields) VALUES (?Values) RETURNING id `, model) return err } func GetUser(db *pg.DB, id int64) (*User, error) { var user User _, err := db.QueryOne(&user, `SELECT * FROM users WHERE id = ?`, id) return &user, err } func GetUsers(db *pg.DB) ([]User, error) { var users []User _, err := db.Query(&users, `SELECT * FROM users`) return users, err } func GetUsersByIds(db *pg.DB, ids []int64) ([]User, error) { var users []User _, err := db.Query(&users, `SELECT * FROM users WHERE id IN (?)`, pg.Ints(ids)) return users, err } type Story struct { Id int64 `pg:",nullempty"` Title string UserId int64 User *User `pg:"-"` } func (s Story) String() string { return fmt.Sprintf("Story<%d %s %s>", s.Id, s.Title, s.User) } func CreateStory(db *pg.DB, story *Story) error { model := pg.NewModel(story, "") _, err := db.QueryOne(model, ` INSERT INTO stories (?Fields) VALUES (?Values) RETURNING id `, model) return err } // GetStory returns story with associated user (author of the story). func GetStory(db *pg.DB, id int64) (*Story, error) { story := &Story{ Id: id, } model := pg.NewModel(story, "s").HasOne("User", "u") _, err := db.QueryOne(model, ` SELECT ?Columns FROM stories AS s, users AS u WHERE s.id = ?id AND u.id = s.user_id `, model) return story, err } func createSchema(db *pg.DB) error { queries := []string{ `CREATE TEMP TABLE users (id serial, name text, emails text[])`, `CREATE TEMP TABLE stories (id serial, title text, user_id bigint)`, } for _, q := range queries { _, err := db.Exec(q) if err != nil { return err } } return nil } func main() { db := pg.Connect(&pg.Options{ User: "postgres", }) err := createSchema(db) if err != nil { panic(err) } user1 := &User{ Name: "admin", Emails: []string{"admin1@admin", "admin2@admin"}, } err = CreateUser(db, user1) if err != nil { panic(err) } err = CreateUser(db, &User{ Name: "root", Emails: []string{"root1@root", "root2@root"}, }) if err != nil { panic(err) } story1 := &Story{ Title: "Cool story", UserId: user1.Id, } err = CreateStory(db, story1) user, err := GetUser(db, user1.Id) if err != nil { panic(err) } users, err := GetUsers(db) if err != nil { panic(err) } story, err := GetStory(db, story1.Id) if err != nil { panic(err) } fmt.Println(story) fmt.Println(user) fmt.Println(users[0], users[1]) }
Output: Story<1 Cool story User<1 admin [admin1@admin admin2@admin]>> User<1 admin [admin1@admin admin2@admin]> User<1 admin [admin1@admin admin2@admin]> User<2 root [root1@root root2@root]>
func (*DB) QueryOne ¶
QueryOne acts like Query, but query must return only one row. It returns ErrNoRows error when query returns zero rows or ErrMultiRows when query returns multiple rows.
Example ¶
var user struct { Name string } res, err := db.QueryOne(&user, ` WITH users (name) AS (VALUES (?)) SELECT * FROM users `, "admin") if err != nil { panic(err) } fmt.Println(res.Affected()) fmt.Println(user)
Output: 1 {admin}
func (*DB) RunInTransaction ¶
RunInTransaction runs a function in a transaction. If function returns an error transaction is rollbacked, otherwise transaction is committed.
func (*DB) WithTimeout ¶
WithTimeout returns a DB that uses d as the read/write timeout.
Example ¶
var count int // Use bigger timeout since this query is known to be slow. _, err := db.WithTimeout(time.Minute).QueryOne(pg.LoadInto(&count), ` SELECT count(*) FROM big_table `) if err != nil { panic(err) }
Output:
type F ¶
type F string
F is a QueryAppender that represents SQL field, e.g. table or column name.
func (F) AppendQuery ¶
type IntegrityError ¶
type IntegrityError struct {
// contains filtered or unexported fields
}
type Ints ¶
type Ints []int64
Example ¶
var nums pg.Ints _, err := db.Query(&nums, `SELECT generate_series(0, 10)`) fmt.Println(nums, err)
Output: [0 1 2 3 4 5 6 7 8 9 10] <nil>
func (Ints) AppendQuery ¶
type Listener ¶
type Listener struct {
// contains filtered or unexported fields
}
Not thread-safe.
Example ¶
ln, err := db.Listen("mychan") if err != nil { panic(err) } wait := make(chan struct{}, 2) go func() { wait <- struct{}{} channel, payload, err := ln.Receive() fmt.Printf("%s %q %v", channel, payload, err) wait <- struct{}{} }() <-wait db.Exec("NOTIFY mychan, ?", "hello world") <-wait
Output: mychan "hello world" <nil>
type Options ¶
type Options struct { // The network type, either tcp or unix. // Default is tcp. Network string Host string Port string User string Password string Database string // Whether to use secure TCP/IP connections (TLS). SSL bool // Run-time configuration parameters to be set on connection. Params map[string]interface{} // The deadline for establishing new connections. If reached, // dial will fail with a timeout. // Default is 5 seconds. DialTimeout time.Duration // The timeout for socket reads. If reached, commands will fail // with a timeout error instead of blocking. // Default is no timeout. ReadTimeout time.Duration // The timeout for socket writes. If reached, commands will fail // with a timeout error instead of blocking. // Default is no timeout. WriteTimeout time.Duration // The maximum number of open socket connections. // Default is 10 connections. PoolSize int // The amount of time client waits for free connection if all // connections are busy before returning an error. // Default is 5 seconds. PoolTimeout time.Duration // The amount of time after which client closes idle connections. // Default is to not close idle connections. IdleTimeout time.Duration // The frequency of idle checks. // Default is 1 minute. IdleCheckFrequency time.Duration }
Database connection options.
type Q ¶
type Q string
Q is a QueryAppender that represents safe SQL query.
func MustFormatQ ¶
func (Q) AppendQuery ¶
func (Q) AppendRawQuery ¶
type QueryAppender ¶
type RawQueryAppender ¶
type Stmt ¶
type Stmt struct {
// contains filtered or unexported fields
}
Stmt is a prepared statement. Stmt is safe for concurrent use by multiple goroutines.
func (*Stmt) ExecOne ¶
ExecOne acts like Exec, but query must affect only one row. It returns ErrNoRows error when query returns zero rows or ErrMultiRows when query returns multiple rows.
type Strings ¶
type Strings []string
Example ¶
var strs pg.Strings _, err := db.Query( &strs, `WITH users AS (VALUES ('foo'), ('bar')) SELECT * FROM users`) fmt.Println(strs, err)
Output: [foo bar] <nil>