PostgreSQL client and ORM for Golang
Basic types: integers, floats, string, bool, time.Time, net.IP, net.IPNet.
sql.NullBool, sql.NullString, sql.NullInt64, sql.NullFloat64 and pg.NullTime .
sql.Scanner and sql/driver.Valuer interfaces.
Structs, maps and arrays are marshalled as JSON by default.
PostgreSQL multidimensional Arrays using array tag and Array wrapper .
Hstore using hstore tag and Hstore wrapper .
Composite types .
All struct fields are nullable by default and zero values (empty string, 0, zero time, empty map or slice) are marshalled as SQL NULL
. sql:",notnull"
tag is used to reverse this behaviour.
Transactions .
Prepared statements .
Notifications using LISTEN
and NOTIFY
.
Copying data using COPY FROM
and COPY TO
.
Timeouts .
Automatic connection pooling with circuit breaker support.
Queries retries on network errors.
Working with models using ORM and SQL .
Scanning variables using ORM and SQL .
SelectOrInsert using on-conflict.
INSERT ... ON CONFLICT DO UPDATE using ORM.
Bulk/batch inserts , updates , and deletes .
Common table expressions using WITH and WrapWith .
CountEstimate using EXPLAIN
to get estimated number of matching rows .
ORM supports has one , belongs to , has many , and many to many with composite/multi-column primary keys.
Soft deletes .
Creating tables from structs .
Pagination and URL filters helpers.
ForEach that calls a function for each row returned by the query without loading all rows into the memory.
Works with PgBouncer in transaction pooling mode.
Migrations .
Sharding .
Model generator from SQL tables .
go get -u github.com/joedursun/pg
package pg_test
import (
"fmt"
"github.com/joedursun/pg"
"github.com/joedursun/pg/orm"
)
type User struct {
Id int64
Name string
Emails []string
}
func (u User ) String () string {
return fmt .Sprintf ("User<%d %s %v>" , u .Id , u .Name , u .Emails )
}
type Story struct {
Id int64
Title string
AuthorId int64
Author * User
}
func (s Story ) String () string {
return fmt .Sprintf ("Story<%d %s %s>" , s .Id , s .Title , s .Author )
}
func ExampleDB_Model () {
db := pg .Connect (& pg.Options {
User : "postgres" ,
})
defer db .Close ()
err := createSchema (db )
if err != nil {
panic (err )
}
user1 := & User {
Name : "admin" ,
Emails : []string {"admin1@admin" , "admin2@admin" },
}
err = db .Insert (user1 )
if err != nil {
panic (err )
}
err = db .Insert (& User {
Name : "root" ,
Emails : []string {"root1@root" , "root2@root" },
})
if err != nil {
panic (err )
}
story1 := & Story {
Title : "Cool story" ,
AuthorId : user1 .Id ,
}
err = db .Insert (story1 )
if err != nil {
panic (err )
}
// Select user by primary key.
user := & User {Id : user1 .Id }
err = db .Select (user )
if err != nil {
panic (err )
}
// Select all users.
var users []User
err = db .Model (& users ).Select ()
if err != nil {
panic (err )
}
// Select story and associated author in one query.
story := new (Story )
err = db .Model (story ).
Relation ("Author" ).
Where ("story.id = ?" , story1 .Id ).
Select ()
if err != nil {
panic (err )
}
fmt .Println (user )
fmt .Println (users )
fmt .Println (story )
// Output: User<1 admin [admin1@admin admin2@admin]>
// [User<1 admin [admin1@admin admin2@admin]> User<2 root [root1@root root2@root]>]
// Story<1 Cool story User<1 admin [admin1@admin admin2@admin]>>
}
func createSchema (db * pg.DB ) error {
for _ , model := range []interface {}{(* User )(nil ), (* Story )(nil )} {
err := db .CreateTable (model , & orm.CreateTableOptions {
Temp : true ,
})
if err != nil {
return err
}
}
return nil
}