Documentation ¶
Overview ¶
Package wpgx helps to improve loading performance and to simplify code.
Package wpgx uses concept of Shaper and Translator interfaces, that helps to map database names with struct fields.
Imagine, we have a simple User struct with an access Role field:
type User struct { ID int `json:"id"` Name string `json:"name"` Role UserRole `json:"role"` } type UserRole struct { ID int `json:"id"` Name string `json:"name"` }
It is business-level objects, let's create a database model:
type userModel struct { ID int Name string RoleID sql.NullInt64 RoleName sql.NullString }
Note that model can have unexported name, it's because we use interfaces in wpgx.
To convert business to database we can implement Extrude method in Shaper interface:
func (u *User) Extrude() wpgx.Translator { return &userModel{ ID: u.ID, Name: u.Name, RoleID: sql.NullInt64{ Int64: int64(u.Role.ID), Valid: u.Role.ID > 0, }, RoleName: sql.NullString{ String: u.Role.Name, Valid: u.Role.Name != "", }, } }
Okay, to convert from database to business we can implement Receive method in Shaper interface:
func (u *User) Receive(item wpgx.Translator) error { m, ok := item.(*userModel) if !ok { return wpgx.ErrUnknownType } u.ID = m.ID u.Name = m.Name // No role selected, set empty if !m.RoleID.Valid { u.Role = UserRole{} return nil } u.Role.ID = int(m.RoleID.Int64) if m.RoleName.Valid { u.Role.Name = m.RoleName.String } return nil }
Now, we can use something like this query to fetch user:
SELECT u.id, u.name, u.role_id, r.name as role_name FROM users u LEFT JOIN roles r ON u.role_id = r.id WHERE u.id = $1;
Let's implement Translator interface to map names:
func (um *userModel) Translate(name string) interface{} { switch name { case "id": return &um.ID case "name": return &um.Name case "role_id": return &um.RoleID case "role_name": return &um.RoleName } return nil }
To create database connection, just call Connect:
db, err := wpgx.Connect("postgresql://user:pass@host:port/database?options") if err != nil { return err }
For performance issues we can to prepare statements but it is not required for select:
sqlSelectUser, err := db.Cook(`query text`) if err != nil { return err }
Now we can load user with ID=42:
var user User if err = db.Load(&user, sqlSelectUser, 42); err != nil { return err }
Okay, but what if we need a list of users? No problems, let's implement Collector interface:
type UserList []*User func (ul *UserList) NewItem() wpgx.Shaper { return new(User) } func (ul *UserList) Collect(item Shaper) error { user, ok := item.(*User) if !ok { return wpgx.ErrUnknownType } *ul = append(*ul, user) return nil }
Now we can select list like this. For example all users with role:
sqlSelectUsers, err := db.Cook(` SELECT u.id, u.name, u.role_id, r.name as role_name FROM users u LEFT JOIN roles r ON u.role_id = r.id WHERE u.role_id IS NOT NULL LIMIT 100; `) if err != nil { return err } users := make(UserList, 0, 100) err = db.Deal(&users, sqlSelectUsers) if err != nil { return err }
Collector can use maps, channels or another type you want.
But what if we need to insert new user and fetch this id? For this task we have to prepare insert query with columns:
sqlInsertUser, err := db.Cook(` INSERT INTO users (name, role_id) VALUES ($1, $2) RETURNING id; `, "name", "role_id") // describe Translator columns for save if err != nil { return err } var ids wpgx.Ints user := &User{Name: "John"} if err = db.Save(user, sqlInsertUser, &ids); err != nil { return err } if len(ids) > 0 { user.ID = ids[0] }
Save uses Collector as result type because you may want to return many rows.
All examples above can be used in one transaction, that called Dealer. Typically Dealer can be used like this:
d, err := db.NewDealer() if err != nil { return err } // Commit when no errors happened defer func(){ d.Jail(err == nil) }() // Doing something good stuff
Good luck!
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrConnClosed = errors.New("connection is closed")
ErrConnClosed occurs when an attemtp to use closed conncection
var ErrUnknownType = errors.New("unknown shaper type")
ErrUnknownType occurs when collector meets unknown shaper type
Functions ¶
func LogLevel ¶
LogLevel is a config helper for use glog as logger godoc: https://godoc.org/github.com/golang/glog
func ReservePath ¶
ReservePath is a config helper to set catalog for saving prepared sql files and uncommitted object data as json files
Types ¶
type Collector ¶
Collector is a generic collection. It can use lists, maps or channels inside
NewItem prepares a translator entity for future loads ¶
Collect puts a new translator item into the inside collection
type Config ¶
type Config struct { ReservePath string pgx.ConnPoolConfig }
Config is just a pgx.ConnPoolConfig with some extra options
type Connector ¶
Connector is the main database connection manager As a Dealer it can execute queries in a default transaction
NewDealer spawns new dealer on the street. It needs to be jailed (closed)
Prepare saves query for further execution ¶
Close closes all free dealers with rollback
type Dealer ¶
type Dealer interface { Cook(text string, cols ...string) (string, error) Deal(result Collector, query string, args ...interface{}) error Load(item Shaper, query string, args ...interface{}) error Save(item Shaper, key string, result Collector) error Jail(commit bool) error }
Dealer is an active subject, like an opened transaction, for query performing
Deal! It executes query and loads result into a data collector. Pass nil when no result needed
Load gets just one item from the database. When no collection needed
Save inserts item into database. Result may need for getting new ID or properties
Jail (aka Close) ends a transaction with commit or rollback respective to the flag
type Ints ¶
type Ints []int
Ints is a simple ints (like ids) collector It is useful in one-time tasks or small scripts, when no models is need
type RawList ¶
RawList is a simple data collector It is useful in one-time tasks or small scripts, when no models is need
type Shaper ¶
type Shaper interface { Extrude() Translator Receive(Translator) error }
Shaper helps to make database model from business model and vice versa
Extrude makes a database model from business data ¶
Receive fills the data from a database model
type Strings ¶
type Strings []string
Strings is a simple strings collector It is useful in one-time tasks or small scripts, when no models is need
type Translator ¶
type Translator interface {
Translate(name string) interface{}
}
Translator helps to isolate model from loading procedure
Translate is intended to associate structure fields with their names