-
-
Notifications
You must be signed in to change notification settings - Fork 269
Expand file tree
/
Copy pathbun.go
More file actions
248 lines (203 loc) · 6.73 KB
/
bun.go
File metadata and controls
248 lines (203 loc) · 6.73 KB
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
package bun
import (
"context"
"fmt"
"reflect"
"github.com/uptrace/bun/internal"
"github.com/uptrace/bun/schema"
)
type (
// Safe marks a SQL fragment as trusted and prevents further escaping.
Safe = schema.Safe
// Name represents a SQL identifier such as a column or table name.
Name = schema.Name
// Ident is a fully qualified SQL identifier.
Ident = schema.Ident
// Order denotes sorting direction used in ORDER BY clauses.
Order = schema.Order
// NullTime is a nullable time value compatible with Bun.
NullTime = schema.NullTime
// BaseModel provides default metadata embedded into user models.
BaseModel = schema.BaseModel
// Query is implemented by all Bun query builders.
Query = schema.Query
// BeforeAppendModelHook is called before a model is appended to a query.
BeforeAppendModelHook = schema.BeforeAppendModelHook
// BeforeScanRowHook runs before scanning an individual row.
BeforeScanRowHook = schema.BeforeScanRowHook
// AfterScanRowHook runs after scanning an individual row.
AfterScanRowHook = schema.AfterScanRowHook
)
const (
// OrderAsc sorts values in ascending order.
OrderAsc = schema.OrderAsc
// OrderAscNullsFirst sorts ascending with NULL values first.
OrderAscNullsFirst = schema.OrderAscNullsFirst
// OrderAscNullsLast sorts ascending with NULL values last.
OrderAscNullsLast = schema.OrderAscNullsLast
// OrderDesc sorts values in descending order.
OrderDesc = schema.OrderDesc
// OrderDescNullsFirst sorts descending with NULL values first.
OrderDescNullsFirst = schema.OrderDescNullsFirst
// OrderDescNullsLast sorts descending with NULL values last.
OrderDescNullsLast = schema.OrderDescNullsLast
)
// SafeQuery wraps a raw query string and arguments and marks it safe for Bun.
func SafeQuery(query string, args ...any) schema.QueryWithArgs {
return schema.SafeQuery(query, args)
}
// BeforeSelectHook is invoked before executing SELECT queries.
type BeforeSelectHook interface {
BeforeSelect(ctx context.Context, query *SelectQuery) error
}
// AfterSelectHook is invoked after executing SELECT queries.
type AfterSelectHook interface {
AfterSelect(ctx context.Context, query *SelectQuery) error
}
// BeforeInsertHook is invoked before executing INSERT queries.
type BeforeInsertHook interface {
BeforeInsert(ctx context.Context, query *InsertQuery) error
}
// AfterInsertHook is invoked after executing INSERT queries.
type AfterInsertHook interface {
AfterInsert(ctx context.Context, query *InsertQuery) error
}
// BeforeUpdateHook is invoked before executing UPDATE queries.
type BeforeUpdateHook interface {
BeforeUpdate(ctx context.Context, query *UpdateQuery) error
}
// AfterUpdateHook is invoked after executing UPDATE queries.
type AfterUpdateHook interface {
AfterUpdate(ctx context.Context, query *UpdateQuery) error
}
// BeforeDeleteHook is invoked before executing DELETE queries.
type BeforeDeleteHook interface {
BeforeDelete(ctx context.Context, query *DeleteQuery) error
}
// AfterDeleteHook is invoked after executing DELETE queries.
type AfterDeleteHook interface {
AfterDelete(ctx context.Context, query *DeleteQuery) error
}
// BeforeCreateTableHook is invoked before executing CREATE TABLE queries.
type BeforeCreateTableHook interface {
BeforeCreateTable(ctx context.Context, query *CreateTableQuery) error
}
// AfterCreateTableHook is invoked after executing CREATE TABLE queries.
type AfterCreateTableHook interface {
AfterCreateTable(ctx context.Context, query *CreateTableQuery) error
}
// BeforeDropTableHook is invoked before executing DROP TABLE queries.
type BeforeDropTableHook interface {
BeforeDropTable(ctx context.Context, query *DropTableQuery) error
}
// AfterDropTableHook is invoked after executing DROP TABLE queries.
type AfterDropTableHook interface {
AfterDropTable(ctx context.Context, query *DropTableQuery) error
}
// SetLogger overwrites default Bun logger.
func SetLogger(logger internal.Logging) {
internal.SetLogger(logger)
}
// In wraps a slice so it can be used with the IN clause.
//
// Deprecated: Use bun.List or bun.Tuple instead.
func In(slice any) schema.QueryAppender {
return schema.In(slice)
}
// NullZero forces zero values to be treated as NULL when building queries.
func NullZero(value any) schema.QueryAppender {
return schema.NullZero(value)
}
//------------------------------------------------------------------------------
// ListValues formats a Go slice as a comma-separated SQL list (e.g., "1, 2, 3").
type ListValues struct {
slice any
}
var _ schema.QueryAppender = ListValues{}
// List creates a ListValues from a Go slice for use in SQL IN expressions.
func List(slice any) ListValues {
return ListValues{
slice: slice,
}
}
// AppendQuery appends the comma-separated list values to the byte slice.
func (in ListValues) AppendQuery(gen schema.QueryGen, b []byte) (_ []byte, err error) {
v := reflect.ValueOf(in.slice)
if v.Kind() != reflect.Slice {
return nil, fmt.Errorf("ch: List(non-slice %T)", in.slice)
}
b = appendValues(gen, b, v)
return b, nil
}
func appendValues(gen schema.QueryGen, b []byte, slice reflect.Value) []byte {
sliceLen := slice.Len()
if sliceLen == 0 {
return append(b, "NULL"...)
}
for i := range sliceLen {
if i > 0 {
b = append(b, ", "...)
}
elem := slice.Index(i)
if elem.Kind() == reflect.Interface {
elem = elem.Elem()
}
b = gen.AppendValue(b, elem)
}
return b
}
//------------------------------------------------------------------------------
// TupleValues formats a Go slice as a parenthesized SQL tuple (e.g., "(1, 2, 3)").
type TupleValues struct {
slice any
}
var _ schema.QueryAppender = TupleValues{}
// Tuple creates a TupleValues from a slice for use in SQL expressions.
func Tuple(slice any) TupleValues {
return TupleValues{
slice: slice,
}
}
// AppendQuery appends the parenthesized tuple to the byte slice.
func (in TupleValues) AppendQuery(gen schema.QueryGen, b []byte) (_ []byte, err error) {
v := reflect.ValueOf(in.slice)
if !v.IsValid() {
b = append(b, "(NULL)"...)
return b, nil
}
if v.Kind() != reflect.Slice {
return nil, fmt.Errorf("ch: Tuple(non-slice %T)", in.slice)
}
b = append(b, '(')
b = appendTuples(gen, b, v)
b = append(b, ')')
return b, nil
}
func appendTuples(gen schema.QueryGen, b []byte, slice reflect.Value) []byte {
sliceLen := slice.Len()
if sliceLen == 0 {
return append(b, "NULL"...)
}
for i := range sliceLen {
if i > 0 {
b = append(b, ", "...)
}
elem := slice.Index(i)
if elem.Kind() == reflect.Interface {
elem = elem.Elem()
}
switch elem.Kind() {
case reflect.Array, reflect.Slice:
if elem.Type().Elem().Kind() == reflect.Uint8 {
b = gen.AppendValue(b, elem)
} else {
b = append(b, '(')
b = appendTuples(gen, b, elem)
b = append(b, ')')
}
default:
b = gen.AppendValue(b, elem)
}
}
return b
}