-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinsert.go
101 lines (80 loc) · 1.98 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
package qry
import (
"fmt"
"strings"
)
func Insert() InsertQuery {
return InsertQuery{}
}
type InsertQuery struct {
Fields []Field
Values [][]any
Table string
Limit int64
Offset int64
}
func (query InsertQuery) Build() (string, []any) {
stmt := fmt.Sprintf(
"INSERT INTO %s",
query.Table,
)
args := make([]any, 0)
stmt += fmt.Sprintf("(%s) ", genericJoin(query.Fields, ", "))
valuesSeparator := ", "
stmt += "VALUES "
for _, rowValues := range query.Values {
args = append(args, rowValues...)
stmt += fmt.Sprintf("(%s) ", strings.TrimRight(strings.Repeat("?"+valuesSeparator, len(rowValues)), valuesSeparator))
}
stmt = strings.TrimSpace(stmt)
if query.Limit > 0 {
stmt += fmt.Sprintf(" LIMIT %d", query.Limit)
}
if query.Offset > 0 {
stmt += fmt.Sprintf(" OFFSET %d", query.Offset)
}
return stmt, args
}
type TypedInsertQuery[T any] struct {
InsertQuery
Values func(target *T) map[Field]any
Targets []*T
}
func findFieldIndex(field Field, columns []Field) int {
for i, f := range columns {
if f == field {
return i
}
}
panic("field not found in columns")
}
func (query TypedInsertQuery[T]) Prepare() InsertQuery {
var columns []Field = nil
values := make([][]any, 0)
for _, target := range query.Targets {
targetValues := query.Values(target)
// Extract the columns of the first target.
// Each target should be returning the same values.
if columns == nil {
columns = make([]Field, len(targetValues))
columnIndex := 0
for k := range targetValues {
columns[columnIndex] = k
columnIndex++
}
}
// Extract the values
rowValues := make([]any, len(targetValues))
for field, v := range targetValues {
rowValueIndex := findFieldIndex(field, columns)
rowValues[rowValueIndex] = v
}
values = append(values, rowValues)
}
query.InsertQuery.Fields = columns
query.InsertQuery.Values = values
return query.InsertQuery
}
func (query TypedInsertQuery[T]) Build() (string, []any) {
return query.Prepare().Build()
}