-
Notifications
You must be signed in to change notification settings - Fork 36
/
insert_builder.go
155 lines (135 loc) · 3.97 KB
/
insert_builder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package dbr
import (
"context"
"database/sql"
"reflect"
)
// InsertBuilder builds "INSERT ..." stmt
type InsertBuilder interface {
Builder
EventReceiver
Executer
Columns(column ...string) InsertBuilder
Values(value ...interface{}) InsertBuilder
Record(structValue interface{}) InsertBuilder
OnConflictMap(constraint string, actions map[string]interface{}) InsertBuilder
OnConflict(constraint string) ConflictStmt
Pair(column string, value interface{}) InsertBuilder
}
// InsertBuilder builds "INSERT ..." stmt
type insertBuilder struct {
EventReceiver
runner
Dialect Dialect
RecordID reflect.Value
insertStmt *insertStmt
ctx context.Context
}
// InsertInto creates a InsertBuilder
func (sess *Session) InsertInto(table string) InsertBuilder {
return &insertBuilder{
runner: sess,
EventReceiver: sess.EventReceiver,
Dialect: sess.Dialect,
insertStmt: createInsertStmt(table),
ctx: sess.ctx,
}
}
// InsertInto creates a InsertBuilder
func (tx *Tx) InsertInto(table string) InsertBuilder {
return &insertBuilder{
runner: tx,
EventReceiver: tx.EventReceiver,
Dialect: tx.Dialect,
insertStmt: createInsertStmt(table),
ctx: tx.ctx,
}
}
// InsertBySql creates a InsertBuilder from raw query
func (sess *Session) InsertBySql(query string, value ...interface{}) InsertBuilder {
return &insertBuilder{
runner: sess,
EventReceiver: sess.EventReceiver,
Dialect: sess.Dialect,
insertStmt: createInsertStmtBySQL(query, value),
ctx: sess.ctx,
}
}
// InsertBySql creates a InsertBuilder from raw query
func (tx *Tx) InsertBySql(query string, value ...interface{}) InsertBuilder {
return &insertBuilder{
runner: tx,
EventReceiver: tx.EventReceiver,
Dialect: tx.Dialect,
insertStmt: createInsertStmtBySQL(query, value),
ctx: tx.ctx,
}
}
func (b *insertBuilder) Build(d Dialect, buf Buffer) error {
return b.insertStmt.Build(d, buf)
}
// Pair adds a new column value pair
func (b *insertBuilder) Pair(column string, value interface{}) InsertBuilder {
b.Columns(column)
switch len(b.insertStmt.Value) {
case 0:
b.insertStmt.Values(value)
case 1:
b.insertStmt.Value[0] = append(b.insertStmt.Value[0], value)
default:
panic("pair only allows one record to insert")
}
return b
}
// Exec executes the stmt with background context
func (b *insertBuilder) Exec() (sql.Result, error) {
return b.ExecContext(b.ctx)
}
// ExecContext executes the stmt
func (b *insertBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
result, err := exec(ctx, b.runner, b.EventReceiver, b, b.Dialect)
if err != nil {
return nil, err
}
if b.RecordID.IsValid() {
if id, err := result.LastInsertId(); err == nil {
b.RecordID.SetInt(id)
}
}
return result, nil
}
// Columns adds columns
func (b *insertBuilder) Columns(column ...string) InsertBuilder {
b.insertStmt.Columns(column...)
return b
}
// Values adds a tuple for columns
func (b *insertBuilder) Values(value ...interface{}) InsertBuilder {
b.insertStmt.Values(value...)
return b
}
// Record adds a tuple for columns from a struct
func (b *insertBuilder) Record(structValue interface{}) InsertBuilder {
v := reflect.Indirect(reflect.ValueOf(structValue))
if v.Kind() == reflect.Struct && v.CanSet() {
// ID is recommended by golint here
for _, name := range []string{"Id", "ID"} {
field := v.FieldByName(name)
if field.IsValid() && field.Kind() == reflect.Int64 {
b.RecordID = field
break
}
}
}
b.insertStmt.Record(structValue)
return b
}
// OnConflictMap allows to add actions for constraint violation, e.g UPSERT
func (b *insertBuilder) OnConflictMap(constraint string, actions map[string]interface{}) InsertBuilder {
b.insertStmt.OnConflictMap(constraint, actions)
return b
}
// OnConflict creates an empty OnConflict section fo insert statement , e.g UPSERT
func (b *insertBuilder) OnConflict(constraint string) ConflictStmt {
return b.insertStmt.OnConflict(constraint)
}