/
insert.go
120 lines (100 loc) · 2.49 KB
/
insert.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
package sqlbuilder
import (
"reflect"
"strings"
"unicode/utf8"
"github.com/FantLab/go-kit/database/sqlapi"
"github.com/FantLab/go-kit/env"
)
func InsertInto(tableName string, records ...interface{}) *sqlapi.Query {
return insertInto(tableName, "db", env.IsDebug(), records)
}
func insertInto(tableName, tagName string, checkTypes bool, records []interface{}) *sqlapi.Query {
var recordType reflect.Type
for _, record := range records {
if recordType == nil {
recordType = reflect.TypeOf(record)
if !checkTypes {
break
}
} else if reflect.TypeOf(record) != recordType {
return nil
}
}
if recordType == nil || recordType.Kind() != reflect.Struct {
return nil
}
fieldNames := extractFieldNames(recordType, tagName)
n, m := len(fieldNames), len(records)
if n == 0 {
return nil
}
args := make([]interface{}, 0, m*n)
for _, record := range records {
value := reflect.ValueOf(record)
for j := 0; j < n; j++ {
args = append(args, value.Field(j).Interface())
}
}
text := makeInsertQueryText(tableName, fieldNames, sqlapi.BindVarChar, m)
return sqlapi.NewQuery(text).WithArgs(args...)
}
func extractFieldNames(typ reflect.Type, tagName string) (fieldNames []string) {
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
name := field.Tag.Get(tagName)
if len(name) == 0 {
name = field.Name
}
fieldNames = append(fieldNames, name)
}
return
}
const (
insertText = "INSERT INTO "
valuesText = " VALUES "
)
func calculateInsertQuerySize(tableName string, fieldNames []string, bindVarChar rune, count int) (size int) {
size += len(insertText)
size += len(tableName)
size++
for i, fieldName := range fieldNames {
if i > 0 {
size++
}
size += len(fieldName)
}
size++
size += len(valuesText)
size += count*(len(fieldNames)*(utf8.RuneLen(bindVarChar)+1)+2) - 1
return
}
func makeInsertQueryText(tableName string, fieldNames []string, bindVarChar rune, count int) string {
var sb strings.Builder
sb.Grow(calculateInsertQuerySize(tableName, fieldNames, bindVarChar, count))
sb.WriteString(insertText)
sb.WriteString(tableName)
sb.WriteRune('(')
for i, fieldName := range fieldNames {
if i > 0 {
sb.WriteRune(',')
}
sb.WriteString(fieldName)
}
sb.WriteRune(')')
sb.WriteString(valuesText)
for i := 0; i < count; i++ {
if i > 0 {
sb.WriteRune(',')
}
sb.WriteRune('(')
for j := 0; j < len(fieldNames); j++ {
if j > 0 {
sb.WriteRune(',')
}
sb.WriteRune(bindVarChar)
}
sb.WriteRune(')')
}
return sb.String()
}