/
insert.go
166 lines (134 loc) · 4.06 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
159
160
161
162
163
164
165
166
package builder
import (
"fmt"
"github.com/ulule/loukoum/stmt"
"github.com/ulule/loukoum/types"
)
// Insert is a builder used for "INSERT" query.
type Insert struct {
insert stmt.Insert
}
// NewInsert creates a new Insert.
func NewInsert() Insert {
return Insert{
insert: stmt.NewInsert(),
}
}
// Into sets the INTO clause of the query.
func (b Insert) Into(into interface{}) Insert {
if !b.insert.Into.IsEmpty() {
panic("loukoum: insert builder has into clause already defined")
}
switch value := into.(type) {
case string:
b.insert.Into = stmt.NewInto(stmt.NewTable(value))
case stmt.Into:
b.insert.Into = value
case stmt.Table:
b.insert.Into = stmt.NewInto(value)
default:
panic(fmt.Sprintf("loukoum: cannot use %T as into clause", into))
}
if b.insert.Into.IsEmpty() {
panic("loukoum: the given into clause is undefined")
}
return b
}
// Columns sets the query columns.
func (b Insert) Columns(columns ...interface{}) Insert {
if len(columns) == 0 {
return b
}
if len(b.insert.Columns) != 0 {
panic("loukoum: insert builder has columns clause already defined")
}
b.insert.Columns = ToColumns(columns)
return b
}
// Values sets the query values.
func (b Insert) Values(values ...interface{}) Insert {
if !b.insert.Values.IsEmpty() {
panic("loukoum: insert builder has values clause already defined")
}
b.insert.Values = stmt.NewValues(stmt.NewArrayExpression(values...))
return b
}
// Returning builds the RETURNING clause.
func (b Insert) Returning(values ...interface{}) Insert {
if !b.insert.Returning.IsEmpty() {
panic("loukoum: insert builder has returning clause already defined")
}
b.insert.Returning = stmt.NewReturning(ToColumns(values))
return b
}
// OnConflict builds the ON CONFLICT clause.
func (b Insert) OnConflict(args ...interface{}) Insert {
if !b.insert.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.insert.OnConflict.Target.Columns = append(b.insert.OnConflict.Target.Columns, ToColumn(value))
case stmt.ConflictNoAction:
b.insert.OnConflict.Action = value
return b
case stmt.ConflictUpdateAction:
if b.insert.OnConflict.Target.IsEmpty() {
panic("loukoum: on conflict update clause requires at least one target")
}
b.insert.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.insert.Columns) != 0 {
panic("loukoum: insert builder has columns clause already defined")
}
if !b.insert.Values.IsEmpty() {
panic("loukoum: insert builder has values clause already defined")
}
pairs := ToSet(args).Pairs
columns, expressions := pairs.Values()
array := stmt.NewArray()
array.AddValues(expressions)
values := stmt.NewValues(array)
b.insert.Columns = columns
b.insert.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 {
var ctx types.RawContext
b.insert.Write(&ctx)
return ctx.Query()
}
// NamedQuery returns the underlying query as a named statement.
func (b Insert) NamedQuery() (string, map[string]interface{}) {
var ctx types.NamedContext
b.insert.Write(&ctx)
return ctx.Query(), ctx.Values()
}
// Query returns the underlying query as a regular statement.
func (b Insert) Query() (string, []interface{}) {
var ctx types.StdContext
b.insert.Write(&ctx)
return ctx.Query(), ctx.Values()
}
// Statement returns underlying statement.
func (b Insert) Statement() stmt.Statement {
return b.insert
}
// Ensure that Insert is a Builder
var _ Builder = Insert{}