-
Notifications
You must be signed in to change notification settings - Fork 535
/
query_mods.go
499 lines (419 loc) · 11.6 KB
/
query_mods.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
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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
package qm
import (
"strings"
"github.com/volatiletech/sqlboiler/queries"
"github.com/volatiletech/sqlboiler/queries/qmhelper"
)
// QueryMod modifies a query object.
type QueryMod interface {
Apply(q *queries.Query)
}
// The QueryModFunc type is an adapter to allow the use
// of ordinary functions for query modifying. If f is a
// function with the appropriate signature,
// QueryModFunc(f) is a QueryMod that calls f.
type QueryModFunc func(q *queries.Query)
// Apply calls f(q).
func (f QueryModFunc) Apply(q *queries.Query) {
f(q)
}
type queryMods []QueryMod
// Apply applies the query mods to a query, satisfying
// the applicator interface in queries. This "clever"
// inversion of dependency is because suddenly the
// eager loading needs to be able to store query mods
// in the query object, which before - never knew about
// query mods.
func (m queryMods) Apply(q *queries.Query) {
Apply(q, m...)
}
// Apply the query mods to the Query object
func Apply(q *queries.Query, mods ...QueryMod) {
for _, mod := range mods {
mod.Apply(q)
}
}
type sqlQueryMod struct {
sql string
args []interface{}
}
// Apply implements QueryMod.Apply.
func (qm sqlQueryMod) Apply(q *queries.Query) {
queries.SetSQL(q, qm.sql, qm.args...)
}
// SQL allows you to execute a plain SQL statement
func SQL(sql string, args ...interface{}) QueryMod {
return sqlQueryMod{
sql: sql,
args: args,
}
}
type loadQueryMod struct {
relationship string
mods []QueryMod
}
// Apply implements QueryMod.Apply.
func (qm loadQueryMod) Apply(q *queries.Query) {
queries.AppendLoad(q, qm.relationship)
if len(qm.mods) != 0 {
queries.SetLoadMods(q, qm.relationship, queryMods(qm.mods))
}
}
// Load allows you to specify foreign key relationships to eager load
// for your query. Passed in relationships need to be in the format
// MyThing or MyThings.
// Relationship name plurality is important, if your relationship is
// singular, you need to specify the singular form and vice versa.
//
// In the following example we see how to eager load a users's videos
// and the video's tags comments, and publisher during a query to find users.
//
// models.Users(qm.Load("Videos.Tags"))
//
// In order to filter better on the query for the relationships you can additionally
// supply query mods.
//
// models.Users(qm.Load("Videos.Tags", Where("deleted = ?", isDeleted)))
//
// Keep in mind the above only sets the query mods for the query on the last specified
// relationship. In this case, only Tags will get the query mod. If you want to do
// intermediate relationships with query mods you must specify them separately:
//
// models.Users(
// qm.Load("Videos", Where("deleted = false"))
// qm.Load("Videos.Tags", Where("deleted = ?", isDeleted))
// )
func Load(relationship string, mods ...QueryMod) QueryMod {
return loadQueryMod{
relationship: relationship,
mods: mods,
}
}
type innerJoinQueryMod struct {
clause string
args []interface{}
}
// Apply implements QueryMod.Apply.
func (qm innerJoinQueryMod) Apply(q *queries.Query) {
queries.AppendInnerJoin(q, qm.clause, qm.args...)
}
// InnerJoin on another table
func InnerJoin(clause string, args ...interface{}) QueryMod {
return innerJoinQueryMod{
clause: clause,
args: args,
}
}
type leftOuterJoinQueryMod struct {
clause string
args []interface{}
}
// Apply implements QueryMod.Apply.
func (qm leftOuterJoinQueryMod) Apply(q *queries.Query) {
queries.AppendLeftOuterJoin(q, qm.clause, qm.args...)
}
// LeftOuterJoin on another table
func LeftOuterJoin(clause string, args ...interface{}) QueryMod {
return leftOuterJoinQueryMod{
clause: clause,
args: args,
}
}
type rightOuterJoinQueryMod struct {
clause string
args []interface{}
}
// Apply implements QueryMod.Apply.
func (qm rightOuterJoinQueryMod) Apply(q *queries.Query) {
queries.AppendRightOuterJoin(q, qm.clause, qm.args...)
}
// RightOuterJoin on another table
func RightOuterJoin(clause string, args ...interface{}) QueryMod {
return rightOuterJoinQueryMod{
clause: clause,
args: args,
}
}
type fullOuterJoinQueryMod struct {
clause string
args []interface{}
}
// Apply implements QueryMod.Apply.
func (qm fullOuterJoinQueryMod) Apply(q *queries.Query) {
queries.AppendFullOuterJoin(q, qm.clause, qm.args...)
}
// FullOuterJoin on another table
func FullOuterJoin(clause string, args ...interface{}) QueryMod {
return fullOuterJoinQueryMod{
clause: clause,
args: args,
}
}
type distinctQueryMod struct {
clause string
}
// Apply implements QueryMod.Apply.
func (qm distinctQueryMod) Apply(q *queries.Query) {
queries.SetDistinct(q, qm.clause)
}
// Distinct allows you to filter duplicates
func Distinct(clause string) QueryMod {
return distinctQueryMod{
clause: clause,
}
}
type withQueryMod struct {
clause string
args []interface{}
}
// Apply implements QueryMod.Apply.
func (qm withQueryMod) Apply(q *queries.Query) {
queries.AppendWith(q, qm.clause, qm.args...)
}
// With allows you to pass in a Common Table Expression clause (and args)
func With(clause string, args ...interface{}) QueryMod {
return withQueryMod{
clause: clause,
args: args,
}
}
type selectQueryMod struct {
columns []string
}
// Apply implements QueryMod.Apply.
func (qm selectQueryMod) Apply(q *queries.Query) {
queries.AppendSelect(q, qm.columns...)
}
// Select specific columns opposed to all columns
func Select(columns ...string) QueryMod {
return selectQueryMod{
columns: columns,
}
}
// Where allows you to specify a where clause for your statement. If multiple
// Where statements are used they are combined with 'and'
func Where(clause string, args ...interface{}) QueryMod {
return qmhelper.WhereQueryMod{
Clause: clause,
Args: args,
}
}
type andQueryMod struct {
clause string
args []interface{}
}
// Apply implements QueryMod.Apply.
func (qm andQueryMod) Apply(q *queries.Query) {
queries.AppendWhere(q, qm.clause, qm.args...)
}
// And allows you to specify a where clause separated by an AND for your statement
// And is a duplicate of the Where function, but allows for more natural looking
// query mod chains, for example: (Where("a=?"), And("b=?"), Or("c=?")))
//
// Because Where statements are by default combined with and, there's no reason
// to call this method as it behaves the same as "Where"
func And(clause string, args ...interface{}) QueryMod {
return andQueryMod{
clause: clause,
args: args,
}
}
type orQueryMod struct {
clause string
args []interface{}
}
// Apply implements QueryMod.Apply.
func (qm orQueryMod) Apply(q *queries.Query) {
queries.AppendWhere(q, qm.clause, qm.args...)
queries.SetLastWhereAsOr(q)
}
// Or allows you to specify a where clause separated by an OR for your statement
func Or(clause string, args ...interface{}) QueryMod {
return orQueryMod{
clause: clause,
args: args,
}
}
// Or2 takes a Where query mod and turns it into an Or. It can be detrimental
// if used on things that are not Where query mods as it will still modify the
// last Where statement into an Or.
func Or2(q QueryMod) QueryMod {
return or2QueryMod{inner: q}
}
type or2QueryMod struct {
inner QueryMod
}
func (qm or2QueryMod) Apply(q *queries.Query) {
qm.inner.Apply(q)
queries.SetLastWhereAsOr(q)
}
// Apply implements QueryMod.Apply.
type whereInQueryMod struct {
clause string
args []interface{}
}
func (qm whereInQueryMod) Apply(q *queries.Query) {
queries.AppendIn(q, qm.clause, qm.args...)
}
// WhereIn allows you to specify a "x IN (set)" clause for your where statement
// Example clauses: "column in ?", "(column1,column2) in ?"
func WhereIn(clause string, args ...interface{}) QueryMod {
return whereInQueryMod{
clause: clause,
args: args,
}
}
type andInQueryMod struct {
clause string
args []interface{}
}
// Apply implements QueryMod.Apply.
func (qm andInQueryMod) Apply(q *queries.Query) {
queries.AppendIn(q, qm.clause, qm.args...)
}
// AndIn allows you to specify a "x IN (set)" clause separated by an AndIn
// for your where statement. AndIn is a duplicate of the WhereIn function, but
// allows for more natural looking query mod chains, for example:
// (WhereIn("column1 in ?"), AndIn("column2 in ?"), OrIn("column3 in ?"))
func AndIn(clause string, args ...interface{}) QueryMod {
return andInQueryMod{
clause: clause,
args: args,
}
}
type orInQueryMod struct {
clause string
args []interface{}
}
// Apply implements QueryMod.Apply.
func (qm orInQueryMod) Apply(q *queries.Query) {
queries.AppendIn(q, qm.clause, qm.args...)
queries.SetLastInAsOr(q)
}
// OrIn allows you to specify an IN clause separated by
// an OR for your where statement
func OrIn(clause string, args ...interface{}) QueryMod {
return orInQueryMod{
clause: clause,
args: args,
}
}
// Expr groups where query mods. It's detrimental to use this with any other
// type of Query Mod because the effects will always only affect where clauses.
//
// When Expr is used, the entire query will stop doing automatic paretheses
// for the where statement and you must use Expr anywhere you would like them.
//
// Do NOT use with anything except where.
func Expr(wheremods ...QueryMod) QueryMod {
return exprMod{mods: wheremods}
}
type exprMod struct {
mods []QueryMod
}
// Apply implements QueryMod.Apply
func (qm exprMod) Apply(q *queries.Query) {
queries.AppendWhereLeftParen(q)
for _, mod := range qm.mods {
mod.Apply(q)
}
queries.AppendWhereRightParen(q)
}
type groupByQueryMod struct {
clause string
}
// Apply implements QueryMod.Apply.
func (qm groupByQueryMod) Apply(q *queries.Query) {
queries.AppendGroupBy(q, qm.clause)
}
// GroupBy allows you to specify a group by clause for your statement
func GroupBy(clause string) QueryMod {
return groupByQueryMod{
clause: clause,
}
}
type orderByQueryMod struct {
clause string
}
// Apply implements QueryMod.Apply.
func (qm orderByQueryMod) Apply(q *queries.Query) {
queries.AppendOrderBy(q, qm.clause)
}
// OrderBy allows you to specify a order by clause for your statement
func OrderBy(clause string) QueryMod {
return orderByQueryMod{
clause: clause,
}
}
type havingQueryMod struct {
clause string
args []interface{}
}
// Apply implements QueryMod.Apply.
func (qm havingQueryMod) Apply(q *queries.Query) {
queries.AppendHaving(q, qm.clause, qm.args...)
}
// Having allows you to specify a having clause for your statement
func Having(clause string, args ...interface{}) QueryMod {
return havingQueryMod{
clause: clause,
args: args,
}
}
type fromQueryMod struct {
from string
}
// Apply implements QueryMod.Apply.
func (qm fromQueryMod) Apply(q *queries.Query) {
queries.AppendFrom(q, qm.from)
}
// From allows to specify the table for your statement
func From(from string) QueryMod {
return fromQueryMod{
from: from,
}
}
type limitQueryMod struct {
limit int
}
// Apply implements QueryMod.Apply.
func (qm limitQueryMod) Apply(q *queries.Query) {
queries.SetLimit(q, qm.limit)
}
// Limit the number of returned rows
func Limit(limit int) QueryMod {
return limitQueryMod{
limit: limit,
}
}
type offsetQueryMod struct {
offset int
}
// Apply implements QueryMod.Apply.
func (qm offsetQueryMod) Apply(q *queries.Query) {
queries.SetOffset(q, qm.offset)
}
// Offset into the results
func Offset(offset int) QueryMod {
return offsetQueryMod{
offset: offset,
}
}
type forQueryMod struct {
clause string
}
// Apply implements QueryMod.Apply.
func (qm forQueryMod) Apply(q *queries.Query) {
queries.SetFor(q, qm.clause)
}
// For inserts a concurrency locking clause at the end of your statement
func For(clause string) QueryMod {
return forQueryMod{
clause: clause,
}
}
// Rels is an alias for strings.Join to make it easier to use relationship name
// constants in Load.
func Rels(r ...string) string {
return strings.Join(r, ".")
}