-
Notifications
You must be signed in to change notification settings - Fork 11
/
insert.go
158 lines (126 loc) · 3.86 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
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
156
157
158
package builder
import (
"fmt"
"github.com/ulule/loukoum/v3/stmt"
"github.com/ulule/loukoum/v3/types"
)
// Insert is a builder used for "INSERT" query.
type Insert struct {
query stmt.Insert
}
// NewInsert creates a new Insert.
func NewInsert() Insert {
return Insert{
query: stmt.NewInsert(),
}
}
// Into sets the INTO clause of the query.
func (b Insert) Into(into interface{}) Insert {
if !b.query.Into.IsEmpty() {
panic("loukoum: insert builder has into clause already defined")
}
b.query.Into = ToInto(into)
return b
}
// Columns sets the query columns.
func (b Insert) Columns(columns ...interface{}) Insert {
if len(columns) == 0 {
return b
}
if len(b.query.Columns) != 0 {
panic("loukoum: insert builder has columns clause already defined")
}
b.query.Columns = ToColumns(columns)
return b
}
// Values sets the query values.
func (b Insert) Values(values ...interface{}) Insert {
if !b.query.Values.IsEmpty() {
panic("loukoum: insert builder has values clause already defined")
}
b.query.Values = stmt.NewValues(stmt.NewArrayExpression(values...))
return b
}
// Returning builds the RETURNING clause.
func (b Insert) Returning(values ...interface{}) Insert {
if !b.query.Returning.IsEmpty() {
panic("loukoum: insert builder has returning clause already defined")
}
b.query.Returning = stmt.NewReturning(ToSelectExpressions(values))
return b
}
// Comment adds comment to the query.
func (b Insert) Comment(comment string) Insert {
b.query.Comment = stmt.NewComment(comment)
return b
}
// OnConflict builds the ON CONFLICT clause.
func (b Insert) OnConflict(args ...interface{}) Insert {
if !b.query.OnConflict.IsEmpty() {
panic("loukoum: insert builder has on conflict clause already defined")
}
if len(args) == 0 {
panic("loukoum: on conflict clause requires arguments")
}
for i := range args {
switch value := args[i].(type) {
case string, stmt.Column:
b.query.OnConflict.Target.Columns = append(b.query.OnConflict.Target.Columns, ToColumn(value))
case stmt.ConflictNoAction:
b.query.OnConflict.Action = value
return b
case stmt.ConflictUpdateAction:
if b.query.OnConflict.Target.IsEmpty() {
panic("loukoum: on conflict update clause requires at least one target")
}
b.query.OnConflict.Action = value
return b
default:
panic(fmt.Sprintf("loukoum: cannot use %T as on conflict clause", args[i]))
}
}
panic("loukoum: on conflict clause requires an action")
}
// Set is a wrapper that defines columns and values clauses using a pair.
func (b Insert) Set(args ...interface{}) Insert {
if len(b.query.Columns) != 0 {
panic("loukoum: insert builder has columns clause already defined")
}
if !b.query.Values.IsEmpty() {
panic("loukoum: insert builder has values clause already defined")
}
pairs := ToSet(args).Pairs
columns, expressions := pairs.Values()
array := stmt.NewArrayExpression(expressions)
values := stmt.NewValues(array)
b.query.Columns = columns
b.query.Values = values
return b
}
// String returns the underlying query as a raw statement.
// This function should be used for debugging since it doesn't escape anything and is completely
// vulnerable to SQL injection.
// You should use either NamedQuery() or Query()...
func (b Insert) String() string {
ctx := &types.RawContext{}
b.query.Write(ctx)
return ctx.Query()
}
// NamedQuery returns the underlying query as a named statement.
func (b Insert) NamedQuery() (string, map[string]interface{}) {
ctx := &types.NamedContext{}
b.query.Write(ctx)
return ctx.Query(), ctx.Values()
}
// Query returns the underlying query as a regular statement.
func (b Insert) Query() (string, []interface{}) {
ctx := &types.StdContext{}
b.query.Write(ctx)
return ctx.Query(), ctx.Values()
}
// Statement returns underlying statement.
func (b Insert) Statement() stmt.Statement {
return b.query
}
// Ensure that Insert is a Builder
var _ Builder = Insert{}