-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjoin.go
More file actions
125 lines (111 loc) · 3.16 KB
/
join.go
File metadata and controls
125 lines (111 loc) · 3.16 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
package squildx
import "fmt"
type joinType string
const (
innerJoin joinType = "INNER JOIN"
leftJoin joinType = "LEFT JOIN"
rightJoin joinType = "RIGHT JOIN"
fullJoin joinType = "FULL JOIN"
crossJoin joinType = "CROSS JOIN"
innerJoinLateral joinType = "INNER JOIN LATERAL"
leftJoinLateral joinType = "LEFT JOIN LATERAL"
crossJoinLateral joinType = "CROSS JOIN LATERAL"
)
type joinClause struct {
joinType joinType
clause paramClause
subQuery Builder
alias string
}
func (b *builder) addJoin(jt joinType, sql string, maps []Params) *builder {
cp := b.clone()
p, err := extractParams(maps)
if err != nil {
cp.err = err
return cp
}
params, prefix, err := parseParams(sql, p)
if err != nil {
cp.err = err
return cp
}
if err := cp.setPrefix(prefix); err != nil {
cp.err = err
return cp
}
for _, j := range cp.joins {
if j.joinType != jt || j.clause.sql != sql {
continue
}
if paramsEqual(j.clause.params, params) {
return cp
}
cp.err = fmt.Errorf("%w: %s %s", ErrDuplicateJoin, jt, sql)
return cp
}
cp.joins = append(cp.joins, joinClause{
joinType: jt,
clause: paramClause{sql: sql, params: params},
})
return cp
}
func (b *builder) InnerJoin(sql string, params ...Params) Builder {
return b.addJoin(innerJoin, sql, params)
}
func (b *builder) LeftJoin(sql string, params ...Params) Builder {
return b.addJoin(leftJoin, sql, params)
}
func (b *builder) RightJoin(sql string, params ...Params) Builder {
return b.addJoin(rightJoin, sql, params)
}
func (b *builder) FullJoin(sql string, params ...Params) Builder {
return b.addJoin(fullJoin, sql, params)
}
func (b *builder) CrossJoin(sql string, params ...Params) Builder {
return b.addJoin(crossJoin, sql, params)
}
func (b *builder) addJoinLateral(jt joinType, sub Builder, alias string, on string, maps []Params) *builder {
cp := b.clone()
p, err := extractParams(maps)
if err != nil {
cp.err = err
return cp
}
params, prefix, err := parseParams(on, p)
if err != nil {
cp.err = err
return cp
}
if err := cp.setPrefix(prefix); err != nil {
cp.err = err
return cp
}
for _, j := range cp.joins {
if j.joinType != jt || j.alias != alias {
continue
}
if j.clause.sql == on && paramsEqual(j.clause.params, params) && buildersEqual(j.subQuery, sub) {
return cp
}
cp.err = fmt.Errorf("%w: %s LATERAL %s", ErrDuplicateJoin, jt, alias)
return cp
}
cp.joins = append(cp.joins, joinClause{
joinType: jt,
clause: paramClause{sql: on, params: params},
subQuery: sub,
alias: alias,
})
return cp
}
func (b *builder) InnerJoinLateral(sub Builder, alias string, on string, params ...Params) Builder {
return b.addJoinLateral(innerJoinLateral, sub, alias, on, params)
}
func (b *builder) LeftJoinLateral(sub Builder, alias string, on string, params ...Params) Builder {
return b.addJoinLateral(leftJoinLateral, sub, alias, on, params)
}
// CrossJoinLateral has no ON clause, so empty sql and nil maps are passed through to
// addJoinLateral where parseParams handles them as a no-op.
func (b *builder) CrossJoinLateral(sub Builder, alias string) Builder {
return b.addJoinLateral(crossJoinLateral, sub, alias, "", nil)
}