Skip to content

Commit

Permalink
Add insert builder (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
sim-wangyan committed Jul 9, 2024
1 parent 64400e4 commit 4539e9e
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 11 deletions.
80 changes: 80 additions & 0 deletions builder_insert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2020 io.xream.sqlxb
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sqlxb

import (
"encoding/json"
"time"
)

type InsertBuilder struct {
bbs []Bb
}

func (b *InsertBuilder) Set(k string, v interface{}) *InsertBuilder {

defer func() *InsertBuilder {
if s := recover(); s != nil {
bytes, _ := json.Marshal(v)
b.bbs = append(b.bbs, Bb{
op: "SET",
key: k,
value: string(bytes),
})
}
return b
}()

switch v.(type) {
case string:
if v.(string) == "" {
return b
}
break
case uint64, uint, int64, int, int32, int16, int8, bool, byte, float64, float32:
if v == 0 {
return b
}
break
case *uint64, *uint, *int64, *int, *int32, *int16, *int8, *bool, *byte, *float64, *float32:
isNil, n := NilOrNumber(v)
if isNil {
return b
}
v = n
break
case time.Time:
ts := v.(time.Time).Format("2006-01-02 15:04:05")
v = ts
break
case interface{}:
bytes, _ := json.Marshal(v)
v = string(bytes)
break
default:
if v == nil {
return b
}
}

b.bbs = append(b.bbs, Bb{
op: "SET",
key: k,
value: v,
})
return b
}
19 changes: 12 additions & 7 deletions builder_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ type UpdateBuilder struct {
func (ub *UpdateBuilder) Set(k string, v interface{}) *UpdateBuilder {

defer func() *UpdateBuilder {
bytes, _ := json.Marshal(v)
ub.bbs = append(ub.bbs, Bb{
op: "SET",
key: k,
value: string(bytes),
})
if s := recover(); s != nil {
bytes, _ := json.Marshal(v)
ub.bbs = append(ub.bbs, Bb{
key: k,
value: string(bytes),
})
}
return ub
}()

Expand All @@ -42,30 +43,34 @@ func (ub *UpdateBuilder) Set(k string, v interface{}) *UpdateBuilder {
if v.(string) == "" {
return ub
}
break
case uint64, uint, int64, int, int32, int16, int8, bool, byte, float64, float32:
if v == 0 {
return ub
}
break
case *uint64, *uint, *int64, *int, *int32, *int16, *int8, *bool, *byte, *float64, *float32:
isNil, n := NilOrNumber(v)
if isNil {
return ub
}
v = n
break
case time.Time:
ts := v.(time.Time).Format("2006-01-02 15:04:05")
v = ts
break
case interface{}:
bytes, _ := json.Marshal(v)
v = string(bytes)
break
default:
if v == nil {
return ub
}
}

ub.bbs = append(ub.bbs, Bb{
op: "SET",
key: k,
value: v,
})
Expand Down
28 changes: 25 additions & 3 deletions builder_x.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
// limitations under the License.
package sqlxb

import "fmt"

// To build sql, like: SELECT DISTINCT f.id FROM foo f INNER_JOIN JOIN (SELECT foo_id FROM bar) b ON b.foo_id = f.id
// Sql for MySQL, Clickhouse....
//
Expand All @@ -27,6 +29,7 @@ type BuilderX struct {
sorts []Sort
resultKeys []string
orFromSql string
inserts *[]Bb
updates *[]Bb
sxs []*FromX
svs []interface{}
Expand All @@ -48,6 +51,8 @@ func Of(tableNameOrPo interface{}) *BuilderX {
x.orFromSql = tableNameOrPo.(string)
case Po:
x.orFromSql = tableNameOrPo.(Po).TableName()
default:
panic("No `func (* Po) TableName() string` of interface Po: " + fmt.Sprintf("%s", tableNameOrPo))
}
}
return x
Expand Down Expand Up @@ -254,17 +259,34 @@ func (x *BuilderX) Last(last string) *BuilderX {
}

func (x *BuilderX) Update(f func(ub *UpdateBuilder)) *BuilderX {
updateBuilder := new(UpdateBuilder)
x.updates = &updateBuilder.bbs
f(updateBuilder)
builder := new(UpdateBuilder)
x.updates = &builder.bbs
f(builder)
return x
}

func (x *BuilderX) Insert(f func(b *InsertBuilder)) *BuilderX {
builder := new(InsertBuilder)
x.inserts = &builder.bbs
f(builder)
return x
}

func (x *BuilderX) Build() *Built {
if x == nil {
panic("sqlxb.Builder is nil")
}

if x.inserts != nil && len(*(x.inserts)) > 0 {
built := Built{
OrFromSql: x.orFromSql,
Inserts: x.inserts,
}
return &built
}

x.optimizeFromBuilder()

built := Built{
ResultKeys: x.resultKeys,
Updates: x.updates,
Expand Down
2 changes: 2 additions & 0 deletions internal/sql_script.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const (
GROUP_BY = " GROUP BY "
HAVING = " HAVING "
SELECT = "SELECT "
INSERT = "INSERT INTO" + " "
VALUES = " VALUES "
UPDATE = "UPDATE "
SET = " SET "
WHERE = " WHERE "
Expand Down
78 changes: 78 additions & 0 deletions sqlxb_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package sqlxb

import (
"fmt"
"strings"
"testing"
)

type Cat struct {
Id int64
M map[string]string
}

type Pet struct {
One Cat
Id int64
}

func (*Pet) TableName() string {
return "t_pet"
}

func TestInsert(t *testing.T) {

t.Run("insert", func(t *testing.T) {

mm := make(map[string]string)
mm["xxxx"] = "zzzzz"

var po Pet
sql, vs := Of(&po).
Insert(func(b *InsertBuilder) {
b.Set("id", 1).Set("one", Cat{
Id: 2,
M: mm,
})
}).
Build().
SqlOfInsert()

if !strings.Contains(sql, "one") {
t.Error("sql erro")
}

fmt.Println(vs)
fmt.Println(sql)
})
}

func TestUpdate(t *testing.T) {

t.Run("update", func(t *testing.T) {
mm := make(map[string]string)
mm["xxxx"] = "zzzzz"

var po Pet
sql, vs := Of(&po).
Update(func(b *UpdateBuilder) {

b.Set("one", Cat{
Id: 2,
M: mm,
})
}).
Eq("id", 2).
Build().
SqlOfUpdate()

if !strings.Contains(sql, "one") {
t.Error("sql erro")
}

fmt.Println(vs)
fmt.Println(sql)

})

}
40 changes: 39 additions & 1 deletion to_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

type Built struct {
ResultKeys []string
Inserts *[]Bb
Updates *[]Bb
Conds []Bb
Sorts []Sort
Expand Down Expand Up @@ -278,9 +279,15 @@ func (built *Built) SqlOfSelect() (string, []interface{}, map[string]string) {
return dataSql, vs, kmp
}

func (built *Built) SqlOfInsert() (string, []interface{}) {
vs := []interface{}{}
sql := built.sqlInsert(&vs)
return sql, vs
}

func (built *Built) SqlOfUpdate() (string, []interface{}) {
vs := []interface{}{}
km := make(map[string]string) //nil for sub From builder,
km := make(map[string]string) //nil for builder,
dataSql, _ := built.sqlData(&vs, km)
return dataSql, vs
}
Expand Down Expand Up @@ -366,3 +373,34 @@ func (built *Built) sqlCount() string {
countSql := built.toSqlCount(sbCount)
return countSql
}

func (built *Built) sqlInsert(vs *[]interface{}) string {

bp := strings.Builder{}
bp.WriteString(INSERT)
bp.WriteString(built.OrFromSql)
bp.WriteString(SPACE)
bp.WriteString(BEGIN_SUB)
length := len(*built.Inserts)
for i := 0; i < length; i++ {
v := (*built.Inserts)[i]
bp.WriteString(v.key)
if i < length-1 {
bp.WriteString(COMMA)
}
*vs = append(*vs, v.value)
}

bp.WriteString(END_SUB)
bp.WriteString(VALUES)
bp.WriteString(BEGIN_SUB)
for i := 0; i < length; i++ {
bp.WriteString(PLACE_HOLDER)
if i < length-1 {
bp.WriteString(COMMA)
}
}
bp.WriteString(END_SUB)

return bp.String()
}

0 comments on commit 4539e9e

Please sign in to comment.