update doc and provide more samples

This commit is contained in:
Huan Du
2017-12-31 00:31:19 +08:00
parent 8378d54eaa
commit 3d80e20960
4 changed files with 126 additions and 25 deletions
+10 -10
View File
@@ -3,7 +3,7 @@
[![Build Status](https://travis-ci.org/huandu/go-sqlbuilder.svg?branch=master)](https://travis-ci.org/huandu/go-sqlbuilder)
[![GoDoc](https://godoc.org/github.com/huandu/go-sqlbuilder?status.svg)](https://godoc.org/github.com/huandu/go-sqlbuilder)
Package `sqlbuilder` provides a set of flexible and powerful SQL string builders. The only goal of this package is to build SQL string with arguments which can be used in `DB#Query` defined in package `database/sql`.
Package `sqlbuilder` provides a set of flexible and powerful SQL string builders. The only goal of this package is to build SQL string with arguments which can be used in `DB#Query` or `DB#Exec` defined in package `database/sql`.
## Install ##
@@ -75,8 +75,8 @@ var userStruct = NewStruct(new(User))
func ExampleStruct() {
// Prepare SELECT query.
// SELECT id, name, status FROM user WHERE id = 1234
sb := userStruct.Select("user")
// SELECT id, name, status FROM user WHERE id = 1234 LIMIT 1
sb := userStruct.SelectFrom("user")
sb.Where(sb.E("id", 1234))
// Execute the query.
@@ -190,16 +190,16 @@ fmt.Println(args)
// [1 2]
```
### Using a special syntax to build SQL ###
### Using special syntax to build SQL ###
Package `sqlbuilder` defines a special syntax to represent an uncompiled SQL internally. If we want to take advantage of the syntax to build customized tools, we can use `Build` to compile it with arguments.
Package `sqlbuilder` defines special syntax to represent an uncompiled SQL internally. If we want to take advantage of the syntax to build customized tools, we can use `Build` to compile it with arguments.
The format string uses a special syntax to represent arguments.
The format string uses special syntax to represent arguments.
* `$?` uses successive arguments passed in the call. It works similar as `%v` in `fmt.Sprintf`.
* `$0` `$1` ... `$n` uses nth-argument passed in the call. Next `$?` will use arguments n+1.
* `${name}` uses a named argument created by `Named` with `name`.
* `$$` represents a `"$"` string.
* `$?` refers successive arguments passed in the call. It works similar as `%v` in `fmt.Sprintf`.
* `$0` `$1` ... `$n` refers nth-argument passed in the call. Next `$?` will use arguments n+1.
* `${name}` refers a named argument created by `Named` with `name`.
* `$$` is a `"$"` string.
```go
sb := sqlbuilder.NewSelectBuilder()
+4 -4
View File
@@ -63,10 +63,10 @@ func (args *Args) add(arg interface{}) int {
//
// The format string uses a special syntax to represent arguments.
//
// $? uses successive arguments passed in the call. It works similar as `%v` in `fmt.Sprintf`.
// $0 $1 ... $n uses nth-argument passed in the call. Next $? will use arguments n+1.
// ${name} uses a named argument created by `Named` with `name`.
// $$ represents a "$" string.
// $? refers successive arguments passed in the call. It works similar as `%v` in `fmt.Sprintf`.
// $0 $1 ... $n refers nth-argument passed in the call. Next $? will use arguments n+1.
// ${name} refers a named argument created by `Named` with `name`.
// $$ is a "$" string.
func (args *Args) Compile(format string) (query string, values []interface{}) {
buf := &bytes.Buffer{}
idx := strings.IndexRune(format, '$')
+5 -5
View File
@@ -94,21 +94,21 @@ func (s *Struct) parse(t reflect.Type) {
}
}
// Select creates a new `SelectBuilder` with table name.
// SelectFrom creates a new `SelectBuilder` with table name.
// By default, all exported fields of the s are listed as columns in SELECT
// and LIMIT is set to 1.
//
// Caller is responsible to set WHERE condition to find right record.
func (s *Struct) Select(table string) *SelectBuilder {
return s.SelectForTag(table, "")
func (s *Struct) SelectFrom(table string) *SelectBuilder {
return s.SelectFromForTag(table, "")
}
// SelectForTag creates a new `SelectBuilder` with table name for a specified tag.
// SelectFromForTag creates a new `SelectBuilder` with table name for a specified tag.
// By default, all fields of the s tagged with tag are listed as columns in SELECT
// and LIMIT is set to 1.
//
// Caller is responsible to set WHERE condition to find right record.
func (s *Struct) SelectForTag(table string, tag string) *SelectBuilder {
func (s *Struct) SelectFromForTag(table string, tag string) *SelectBuilder {
sb := NewSelectBuilder()
sb.From(table)
sb.Limit(1)
+107 -6
View File
@@ -18,8 +18,8 @@ type structUserForTest struct {
var userForTest = NewStruct(new(structUserForTest))
func TestStructSelect(t *testing.T) {
sb := userForTest.Select("user")
func TestStructSelectFrom(t *testing.T) {
sb := userForTest.SelectFrom("user")
sql, args := sb.Build()
if expected := "SELECT id, Name, status, created_at FROM user LIMIT 1"; expected != sql {
@@ -31,8 +31,8 @@ func TestStructSelect(t *testing.T) {
}
}
func TestStructSelectForTag(t *testing.T) {
sb := userForTest.SelectForTag("user", "important")
func TestStructSelectFromForTag(t *testing.T) {
sb := userForTest.SelectFromForTag("user", "important")
sql, args := sb.Build()
if expected := "SELECT id, Name, status FROM user LIMIT 1"; expected != sql {
@@ -189,6 +189,19 @@ type User struct {
Status int `db:"status"`
}
type Order struct {
ID int64 `db:"id" fieldtag:"new"`
State State `db:"state" fieldtag:"new,paid,done"`
SkuID int64 `db:"sku_id" fieldtag:"new"`
UserID int64 `db:"user_id" fieldtag:"new"`
Price int64 `db:"price" fieldtag:"new,update"`
Discount int64 `db:"discount" fieldtag:"new,update"`
Description string `db:"description" fieldtag:"new,update"`
CreatedAt int64 `db:"created_at" fieldtag:"new"`
ModifiedAt int64 `db:"modified_at" fieldtag:"new,update,paid,done"`
}
type State int
type testDB int
type testRows int
@@ -210,9 +223,16 @@ func (rows testRows) Scan(dest ...interface{}) error {
}
var userStruct = NewStruct(new(User))
var orderStruct = NewStruct(new(Order))
var db testDB
func ExampleStruct_buildSELECTAndUseItAsORM() {
const (
OrderStateInvalid State = iota
OrderStateCreated
OrderStatePaid
)
func ExampleStruct_useStructAsORM() {
// Suppose we defined following type and global variable.
//
// type User struct {
@@ -224,7 +244,7 @@ func ExampleStruct_buildSELECTAndUseItAsORM() {
// var userStruct = NewStruct(new(User))
// Prepare SELECT query.
sb := userStruct.Select("user")
sb := userStruct.SelectFrom("user")
sb.Where(sb.E("id", 1234))
// Execute the query.
@@ -246,6 +266,87 @@ func ExampleStruct_buildSELECTAndUseItAsORM() {
// sqlbuilder.User{ID:1234, Name:"huandu", Status:1}
}
func ExampleStruct_useTag() {
// Suppose we defined following type and global variable.
//
// type Order struct {
// ID int64 `db:"id" fieldtag:"update,paid"`
// State int `db:"state" fieldtag:"paid"`
// SkuID int64 `db:"sku_id"`
// UserID int64 `db:"user_id"`
// Price int64 `db:"price" fieldtag:"update"`
// Discount int64 `db:"discount" fieldtag:"update"`
// Description string `db:"description" fieldtag:"update"`
// CreatedAt int64 `db:"created_at"`
// ModifiedAt int64 `db:"modified_at" fieldtag:"update,paid"`
// }
//
// var orderStruct = NewStruct(new(Order))
createOrder := func(table string) {
order := &Order{
ID: 1234,
State: OrderStateCreated,
SkuID: 5678,
UserID: 7527,
Price: 1000,
Discount: 0,
Description: "Best goods",
CreatedAt: 1234567890,
ModifiedAt: 1234567890,
}
b := orderStruct.InsertInto(table, &order)
sql, args := b.Build()
db.Exec(sql, args)
}
updatePrice := func(table string) {
tag := "update"
var order Order
sql, args := orderStruct.SelectFromForTag(table, tag).Where("id = 1234").Build()
rows, _ := db.Query(sql, args...)
rows.Scan(orderStruct.AddrForTag(tag, &order)...)
// Discount for this user.
// Use tag "update" to update necessary columns only.
order.Discount += 100
b := orderStruct.UpdateForTag(table, tag, &order)
b.Where(b.E("id", order.ID))
sql, args = b.Build()
db.Exec(sql, args...)
}
updateState := func(table string) {
tag := "paid"
var order Order
sql, args := orderStruct.SelectFromForTag(table, tag).Where("id = 1234").Build()
rows, _ := db.Query(sql, args...)
rows.Scan(orderStruct.AddrForTag(tag, &order)...)
// Update state to paid when user has paid for the order.
// Use tag "paid" to update necessary columns only.
if order.State != OrderStateCreated {
// Report state error here.
return
}
order.State = OrderStatePaid
b := orderStruct.UpdateForTag(table, tag, &order)
b.Where(b.E("id", order.ID))
sql, args = b.Build()
db.Exec(sql, args...)
}
table := "order"
createOrder(table)
updatePrice(table)
updateState(table)
fmt.Println("done")
// Output:
// done
}
func ExampleStruct_buildUPDATE() {
// Suppose we defined following type and global variable.
//