Skip to content
This repository has been archived by the owner on Nov 27, 2023. It is now read-only.

Commit

Permalink
新增 Patch 與 Omit 功能
Browse files Browse the repository at this point in the history
  • Loading branch information
YamiOdymel committed Nov 19, 2019
1 parent bd313bd commit 00f55aa
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 3 deletions.
51 changes: 48 additions & 3 deletions query.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ type Query struct {
lockMethod string
query string
params []interface{}
omits []string
}

//=======================================================
Expand Down Expand Up @@ -197,18 +198,30 @@ func (b Query) buildWhere(typ string) (query string) {
}

// buildUpdate 會建置 `UPDATE` 的 SQL 指令。
func (b Query) buildUpdate(data interface{}) (query string) {
func (b Query) buildUpdate(data interface{}, skipZeroValue bool) (query string) {
var set string
beforeOptions, _ := b.buildQueryOptions()
query = fmt.Sprintf("UPDATE %s%s SET ", beforeOptions, b.tableName[0])

switch realData := data.(type) {
case map[string]interface{}:
for column, value := range realData {
if b.isOmitted(column) {
continue
}
if skipZeroValue && value == reflect.Zero(reflect.TypeOf(value)).Interface() {
continue
}
set += fmt.Sprintf("%s = %s, ", column, b.bindParam(value))
}
default:
b.rangeStruct(realData, func(column string, value interface{}) {
if b.isOmitted(column) {
return
}
if skipZeroValue && value == reflect.Zero(reflect.TypeOf(value)).Interface() {
return
}
set += fmt.Sprintf("%s = %s, ", column, b.bindParam(value))
})
}
Expand Down Expand Up @@ -439,6 +452,16 @@ func (b Query) rangeStruct(s interface{}, handler func(column string, value inte
}
}

// isOmitted 會回傳指定欄位是否被指定為忽略。
func (b Query) isOmitted(field string) bool {
for _, v := range b.omits {
if v == field {
return true
}
}
return false
}

// buildInsert 會建置 `INSERT INTO` 的 SQL 指令。
func (b Query) buildInsert(operator string, data interface{}) (query string) {
var columns, values string
Expand All @@ -448,6 +471,9 @@ func (b Query) buildInsert(operator string, data interface{}) (query string) {
switch realData := data.(type) {
case map[string]interface{}:
for column, value := range realData {
if b.isOmitted(column) {
continue
}
columns += fmt.Sprintf("%s, ", column)
values += fmt.Sprintf("%s, ", b.bindParam(value))
}
Expand All @@ -457,6 +483,9 @@ func (b Query) buildInsert(operator string, data interface{}) (query string) {
var columnNames []string
// 先取得欄位的名稱,這樣才能照順序遍歷整個 `map`。
for name := range realData[0] {
if b.isOmitted(name) {
continue
}
columnNames = append(columnNames, name)
// 先建置欄位名稱的 SQL 指令片段。
columns += fmt.Sprintf("%s, ", name)
Expand All @@ -472,6 +501,9 @@ func (b Query) buildInsert(operator string, data interface{}) (query string) {

default:
b.rangeStruct(realData, func(column string, value interface{}) {
if b.isOmitted(column) {
return
}
columns += fmt.Sprintf("%s, ", column)
values += fmt.Sprintf("%s, ", b.bindParam(value))
})
Expand Down Expand Up @@ -598,7 +630,14 @@ func (b Query) Replace(data interface{}) (query string, params []interface{}) {

// Update 會以指定的資料來更新相對應的資料列。
func (b Query) Update(data interface{}) (query string, params []interface{}) {
b.query = b.buildUpdate(data)
b.query = b.buildUpdate(data, false)
query, params = b.runQuery()
return
}

// Patch 會以片段更新的方式處理傳入的資料,任何零值會被忽略而不納入更新範圍。
func (b Query) Patch(data interface{}) (query string, params []interface{}) {
b.query = b.buildUpdate(data, true)
query, params = b.runQuery()
return
}
Expand All @@ -616,6 +655,12 @@ func (b Query) OnDuplicate(columns []string, lastInsertID ...string) Query {
// 限制函式
//=======================================================

// Omit 會省略執行時的某些欄位。
func (b Query) Omit(columns ...string) Query {
b.omits = columns
return b
}

// Limit 能夠在 SQL 查詢指令中建立限制筆數的條件。
func (b Query) Limit(from int, count ...int) Query {
if len(count) == 0 {
Expand All @@ -626,7 +671,7 @@ func (b Query) Limit(from int, count ...int) Query {
return b
}

// Limit 能夠在 SQL 查詢指令中建立限制筆數的條件。
// Offset 能夠在 SQL 查詢指令中建立限制筆數的條件。
func (b Query) Offset(count int, offset int) Query {
b.offset = []int{count, offset}
return b
Expand Down
81 changes: 81 additions & 0 deletions query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,43 @@ func TestInsertMulti(t *testing.T) {
assertEqual(assert, "INSERT INTO Users (Password, Username) VALUES (?, ?), (?, ?)", query)
}

func TestInsertStructOmit(t *testing.T) {
u := struct {
Username string
Password string
}{
Username: "YamiOdymel",
Password: "test",
}
assert := assert.New(t)
query, _ := builder.Table("Users").Omit("Username").Insert(u)
assertEqual(assert, "INSERT INTO Users (Password) VALUES (?)", query)
}

func TestInsertOmit(t *testing.T) {
assert := assert.New(t)
query, _ := builder.Table("Users").Omit("Username").Insert(map[string]interface{}{
"Username": "YamiOdymel",
"Password": "test",
})
assertEqual(assert, "INSERT INTO Users (Password) VALUES (?)", query)
}

func TestInsertMultiOmit(t *testing.T) {
assert := assert.New(t)
data := []map[string]interface{}{
{
"Username": "YamiOdymel",
"Password": "test",
}, {
"Username": "Karisu",
"Password": "12345",
},
}
query, _ := builder.Table("Users").Omit("Username").InsertMulti(data)
assertEqual(assert, "INSERT INTO Users (Password) VALUES (?), (?)", query)
}

func TestReplace(t *testing.T) {
assert := assert.New(t)
query, _ := builder.Table("Users").Replace(map[string]interface{}{
Expand Down Expand Up @@ -132,6 +169,28 @@ func TestOnDuplicateInsert(t *testing.T) {
assertEqual(assert, "INSERT INTO Users (Password, UpdatedAt, Username) VALUES (?, NOW(), ?) ON DUPLICATE KEY UPDATE ID=LAST_INSERT_ID(ID), UpdatedAt = VALUES(UpdatedAt)", query)
}

func TestUpdateOmit(t *testing.T) {
assert := assert.New(t)
query, _ := builder.Table("Users").Where("Username", "YamiOdymel").Omit("Username").Update(map[string]interface{}{
"Username": "Karisu",
"Password": "123456",
})
assertEqual(assert, "UPDATE Users SET Password = ? WHERE Username = ?", query)
}

func TestUpdateOmitStruct(t *testing.T) {
u := struct {
Username string
Password string
}{
Username: "YamiOdymel",
Password: "test",
}
assert := assert.New(t)
query, _ := builder.Table("Users").Where("Username", "YamiOdymel").Omit("Username").Update(u)
assertEqual(assert, "UPDATE Users SET Password = ? WHERE Username = ?", query)
}

func TestUpdate(t *testing.T) {
assert := assert.New(t)
query, _ := builder.Table("Users").Where("Username", "YamiOdymel").Update(map[string]interface{}{
Expand All @@ -154,6 +213,28 @@ func TestUpdateStruct(t *testing.T) {
assertEqual(assert, "UPDATE Users SET Password = ?, Username = ? WHERE Username = ?", query)
}

func TestPatch(t *testing.T) {
assert := assert.New(t)
query, _ := builder.Table("Users").Where("Username", "YamiOdymel").Patch(map[string]interface{}{
"Username": "",
"Password": "123456",
})
assertEqual(assert, "UPDATE Users SET Password = ? WHERE Username = ?", query)
}

func TestPatchStruct(t *testing.T) {
u := struct {
Username string
Password string
}{
Username: "",
Password: "test",
}
assert := assert.New(t)
query, _ := builder.Table("Users").Where("Username", "YamiOdymel").Patch(u)
assertEqual(assert, "UPDATE Users SET Password = ? WHERE Username = ?", query)
}

func TestLimitUpdate(t *testing.T) {
assert := assert.New(t)
query, _ := builder.Table("Users").Limit(10).Update(map[string]interface{}{
Expand Down

0 comments on commit 00f55aa

Please sign in to comment.