1 package sqlgen
2
3 import (
4 "github.com/doug-martin/goqu/v9/exp"
5 "github.com/doug-martin/goqu/v9/internal/errors"
6 "github.com/doug-martin/goqu/v9/internal/sb"
7 )
8
9 type (
10
11
12 SelectSQLGenerator interface {
13 Dialect() string
14 Generate(b sb.SQLBuilder, clauses exp.SelectClauses)
15 }
16
17
18
19 selectSQLGenerator struct {
20 CommonSQLGenerator
21 }
22 )
23
24 func ErrNotSupportedJoinType(j exp.JoinExpression) error {
25 return errors.New("dialect does not support %v", j.JoinType())
26 }
27
28 func ErrJoinConditionRequired(j exp.JoinExpression) error {
29 return errors.New("join condition required for conditioned join %v", j.JoinType())
30 }
31
32 func ErrDistinctOnNotSupported(dialect string) error {
33 return errors.New("dialect does not support DISTINCT ON clause [dialect=%s]", dialect)
34 }
35
36 func ErrWindowNotSupported(dialect string) error {
37 return errors.New("dialect does not support WINDOW clause [dialect=%s]", dialect)
38 }
39
40 var ErrNoWindowName = errors.New("window expresion has no valid name")
41
42 func NewSelectSQLGenerator(dialect string, do *SQLDialectOptions) SelectSQLGenerator {
43 return &selectSQLGenerator{NewCommonSQLGenerator(dialect, do)}
44 }
45
46 func (ssg *selectSQLGenerator) Generate(b sb.SQLBuilder, clauses exp.SelectClauses) {
47 for _, f := range ssg.DialectOptions().SelectSQLOrder {
48 if b.Error() != nil {
49 return
50 }
51 switch f {
52 case CommonTableSQLFragment:
53 ssg.ExpressionSQLGenerator().Generate(b, clauses.CommonTables())
54 case SelectSQLFragment:
55 ssg.SelectSQL(b, clauses)
56 case SelectWithLimitSQLFragment:
57 ssg.SelectWithLimitSQL(b, clauses)
58 case FromSQLFragment:
59 ssg.FromSQL(b, clauses.From())
60 case JoinSQLFragment:
61 ssg.JoinSQL(b, clauses.Joins())
62 case WhereSQLFragment:
63 ssg.WhereSQL(b, clauses.Where())
64 case GroupBySQLFragment:
65 ssg.GroupBySQL(b, clauses.GroupBy())
66 case HavingSQLFragment:
67 ssg.HavingSQL(b, clauses.Having())
68 case WindowSQLFragment:
69 ssg.WindowSQL(b, clauses.Windows())
70 case CompoundsSQLFragment:
71 ssg.CompoundsSQL(b, clauses.Compounds())
72 case OrderSQLFragment:
73 ssg.OrderSQL(b, clauses.Order())
74 case OrderWithOffsetFetchSQLFragment:
75 ssg.OrderWithOffsetFetchSQL(b, clauses.Order(), clauses.Offset(), clauses.Limit())
76 case LimitSQLFragment:
77 ssg.LimitSQL(b, clauses.Limit())
78 case OffsetSQLFragment:
79 ssg.OffsetSQL(b, clauses.Offset())
80 case ForSQLFragment:
81 ssg.ForSQL(b, clauses.Lock())
82 default:
83 b.SetError(ErrNotSupportedFragment("SELECT", f))
84 }
85 }
86 }
87
88 func (ssg *selectSQLGenerator) selectSQLCommon(b sb.SQLBuilder, clauses exp.SelectClauses) {
89 dc := clauses.Distinct()
90 if dc != nil {
91 b.Write(ssg.DialectOptions().DistinctFragment)
92 if !dc.IsEmpty() {
93 if ssg.DialectOptions().SupportsDistinctOn {
94 b.Write(ssg.DialectOptions().OnFragment).WriteRunes(ssg.DialectOptions().LeftParenRune)
95 ssg.ExpressionSQLGenerator().Generate(b, dc)
96 b.WriteRunes(ssg.DialectOptions().RightParenRune, ssg.DialectOptions().SpaceRune)
97 } else {
98 b.SetError(ErrDistinctOnNotSupported(ssg.Dialect()))
99 return
100 }
101 } else {
102 b.WriteRunes(ssg.DialectOptions().SpaceRune)
103 }
104 }
105
106 if cols := clauses.Select(); clauses.IsDefaultSelect() || len(cols.Columns()) == 0 {
107 b.WriteRunes(ssg.DialectOptions().StarRune)
108 } else {
109 ssg.ExpressionSQLGenerator().Generate(b, cols)
110 }
111 }
112
113
114 func (ssg *selectSQLGenerator) SelectSQL(b sb.SQLBuilder, clauses exp.SelectClauses) {
115 b.Write(ssg.DialectOptions().SelectClause).WriteRunes(ssg.DialectOptions().SpaceRune)
116 ssg.selectSQLCommon(b, clauses)
117 }
118
119
120 func (ssg *selectSQLGenerator) SelectWithLimitSQL(b sb.SQLBuilder, clauses exp.SelectClauses) {
121 b.Write(ssg.DialectOptions().SelectClause).WriteRunes(ssg.DialectOptions().SpaceRune)
122 if clauses.Offset() == 0 && clauses.Limit() != nil {
123 ssg.LimitSQL(b, clauses.Limit())
124 b.WriteRunes(ssg.DialectOptions().SpaceRune)
125 }
126 ssg.selectSQLCommon(b, clauses)
127 }
128
129
130 func (ssg *selectSQLGenerator) JoinSQL(b sb.SQLBuilder, joins exp.JoinExpressions) {
131 if len(joins) > 0 {
132 for _, j := range joins {
133 joinType, ok := ssg.DialectOptions().JoinTypeLookup[j.JoinType()]
134 if !ok {
135 b.SetError(ErrNotSupportedJoinType(j))
136 return
137 }
138 b.Write(joinType)
139 ssg.ExpressionSQLGenerator().Generate(b, j.Table())
140 if t, ok := j.(exp.ConditionedJoinExpression); ok {
141 if t.IsConditionEmpty() {
142 b.SetError(ErrJoinConditionRequired(j))
143 return
144 }
145 ssg.joinConditionSQL(b, t.Condition())
146 }
147 }
148 }
149 }
150
151
152 func (ssg *selectSQLGenerator) GroupBySQL(b sb.SQLBuilder, groupBy exp.ColumnListExpression) {
153 if groupBy != nil && len(groupBy.Columns()) > 0 {
154 b.Write(ssg.DialectOptions().GroupByFragment)
155 ssg.ExpressionSQLGenerator().Generate(b, groupBy)
156 }
157 }
158
159
160 func (ssg *selectSQLGenerator) HavingSQL(b sb.SQLBuilder, having exp.ExpressionList) {
161 if having != nil && len(having.Expressions()) > 0 {
162 b.Write(ssg.DialectOptions().HavingFragment)
163 ssg.ExpressionSQLGenerator().Generate(b, having)
164 }
165 }
166
167
168 func (ssg *selectSQLGenerator) OffsetSQL(b sb.SQLBuilder, offset uint) {
169 if offset > 0 {
170 b.Write(ssg.DialectOptions().OffsetFragment)
171 ssg.ExpressionSQLGenerator().Generate(b, offset)
172 }
173 }
174
175
176 func (ssg *selectSQLGenerator) CompoundsSQL(b sb.SQLBuilder, compounds []exp.CompoundExpression) {
177 for _, compound := range compounds {
178 ssg.ExpressionSQLGenerator().Generate(b, compound)
179 }
180 }
181
182
183 func (ssg *selectSQLGenerator) ForSQL(b sb.SQLBuilder, lockingClause exp.Lock) {
184 if lockingClause == nil {
185 return
186 }
187 switch lockingClause.Strength() {
188 case exp.ForNolock:
189 return
190 case exp.ForUpdate:
191 b.Write(ssg.DialectOptions().ForUpdateFragment)
192 case exp.ForNoKeyUpdate:
193 b.Write(ssg.DialectOptions().ForNoKeyUpdateFragment)
194 case exp.ForShare:
195 b.Write(ssg.DialectOptions().ForShareFragment)
196 case exp.ForKeyShare:
197 b.Write(ssg.DialectOptions().ForKeyShareFragment)
198 }
199
200 of := lockingClause.Of()
201 if ofLen := len(of); ofLen > 0 {
202 if ofFragment := ssg.DialectOptions().OfFragment; len(ofFragment) > 0 {
203 b.Write(ofFragment)
204 for i, table := range of {
205 ssg.ExpressionSQLGenerator().Generate(b, table)
206 if i < ofLen-1 {
207 b.WriteRunes(ssg.DialectOptions().CommaRune, ssg.DialectOptions().SpaceRune)
208 }
209 }
210 b.WriteRunes(ssg.DialectOptions().SpaceRune)
211 }
212 }
213
214
215
216 switch lockingClause.WaitOption() {
217 case exp.Wait:
218 return
219 case exp.NoWait:
220 b.Write(ssg.DialectOptions().NowaitFragment)
221 case exp.SkipLocked:
222 b.Write(ssg.DialectOptions().SkipLockedFragment)
223 }
224 }
225
226 func (ssg *selectSQLGenerator) WindowSQL(b sb.SQLBuilder, windows []exp.WindowExpression) {
227 weLen := len(windows)
228 if weLen == 0 {
229 return
230 }
231 if !ssg.DialectOptions().SupportsWindowFunction {
232 b.SetError(ErrWindowNotSupported(ssg.Dialect()))
233 return
234 }
235 b.Write(ssg.DialectOptions().WindowFragment)
236 for i, we := range windows {
237 if !we.HasName() {
238 b.SetError(ErrNoWindowName)
239 }
240 ssg.ExpressionSQLGenerator().Generate(b, we)
241 if i < weLen-1 {
242 b.WriteRunes(ssg.DialectOptions().CommaRune, ssg.DialectOptions().SpaceRune)
243 }
244 }
245 }
246
247 func (ssg *selectSQLGenerator) joinConditionSQL(b sb.SQLBuilder, jc exp.JoinCondition) {
248 switch t := jc.(type) {
249 case exp.JoinOnCondition:
250 ssg.joinOnConditionSQL(b, t)
251 case exp.JoinUsingCondition:
252 ssg.joinUsingConditionSQL(b, t)
253 }
254 }
255
256 func (ssg *selectSQLGenerator) joinUsingConditionSQL(b sb.SQLBuilder, jc exp.JoinUsingCondition) {
257 b.Write(ssg.DialectOptions().UsingFragment).
258 WriteRunes(ssg.DialectOptions().LeftParenRune)
259 ssg.ExpressionSQLGenerator().Generate(b, jc.Using())
260 b.WriteRunes(ssg.DialectOptions().RightParenRune)
261 }
262
263 func (ssg *selectSQLGenerator) joinOnConditionSQL(b sb.SQLBuilder, jc exp.JoinOnCondition) {
264 b.Write(ssg.DialectOptions().OnFragment)
265 ssg.ExpressionSQLGenerator().Generate(b, jc.On())
266 }
267
View as plain text