-
Notifications
You must be signed in to change notification settings - Fork 123
/
flavor.go
205 lines (176 loc) · 5.21 KB
/
flavor.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
// Copyright 2018 Huan Du. All rights reserved.
// Licensed under the MIT license that can be found in the LICENSE file.
package sqlbuilder
import (
"errors"
"fmt"
)
// Supported flavors.
const (
invalidFlavor Flavor = iota
MySQL
PostgreSQL
SQLite
SQLServer
CQL
ClickHouse
Presto
Oracle
Informix
)
var (
// DefaultFlavor is the default flavor for all builders.
DefaultFlavor = MySQL
)
var (
// ErrInterpolateNotImplemented means the method or feature is not implemented right now.
ErrInterpolateNotImplemented = errors.New("go-sqlbuilder: interpolation for this flavor is not implemented")
// ErrInterpolateMissingArgs means there are some args missing in query, so it's not possible to
// prepare a query with such args.
ErrInterpolateMissingArgs = errors.New("go-sqlbuilder: not enough args when interpolating")
// ErrInterpolateUnsupportedArgs means that some types of the args are not supported.
ErrInterpolateUnsupportedArgs = errors.New("go-sqlbuilder: unsupported args when interpolating")
)
// Flavor is the flag to control the format of compiled sql.
type Flavor int
// String returns the name of f.
func (f Flavor) String() string {
switch f {
case MySQL:
return "MySQL"
case PostgreSQL:
return "PostgreSQL"
case SQLite:
return "SQLite"
case SQLServer:
return "SQLServer"
case CQL:
return "CQL"
case ClickHouse:
return "ClickHouse"
case Presto:
return "Presto"
case Oracle:
return "Oracle"
case Informix:
return "Informix"
}
return "<invalid>"
}
// Interpolate parses sql returned by `Args#Compile` or `Builder`,
// and interpolate args to replace placeholders in the sql.
//
// If there are some args missing in sql, e.g. the number of placeholders are larger than len(args),
// returns ErrMissingArgs error.
func (f Flavor) Interpolate(sql string, args []interface{}) (string, error) {
switch f {
case MySQL:
return mysqlInterpolate(sql, args...)
case PostgreSQL:
return postgresqlInterpolate(sql, args...)
case SQLite:
return sqliteInterpolate(sql, args...)
case SQLServer:
return sqlserverInterpolate(sql, args...)
case CQL:
return cqlInterpolate(sql, args...)
case ClickHouse:
return clickhouseInterpolate(sql, args...)
case Presto:
return prestoInterpolate(sql, args...)
case Oracle:
return oracleInterpolate(sql, args...)
case Informix:
return informixInterpolate(sql, args...)
}
return "", ErrInterpolateNotImplemented
}
// NewCreateTableBuilder creates a new CREATE TABLE builder with flavor.
func (f Flavor) NewCreateTableBuilder() *CreateTableBuilder {
b := newCreateTableBuilder()
b.SetFlavor(f)
return b
}
// NewDeleteBuilder creates a new DELETE builder with flavor.
func (f Flavor) NewDeleteBuilder() *DeleteBuilder {
b := newDeleteBuilder()
b.SetFlavor(f)
return b
}
// NewInsertBuilder creates a new INSERT builder with flavor.
func (f Flavor) NewInsertBuilder() *InsertBuilder {
b := newInsertBuilder()
b.SetFlavor(f)
return b
}
// NewSelectBuilder creates a new SELECT builder with flavor.
func (f Flavor) NewSelectBuilder() *SelectBuilder {
b := newSelectBuilder()
b.SetFlavor(f)
return b
}
// NewUpdateBuilder creates a new UPDATE builder with flavor.
func (f Flavor) NewUpdateBuilder() *UpdateBuilder {
b := newUpdateBuilder()
b.SetFlavor(f)
return b
}
// NewUnionBuilder creates a new UNION builder with flavor.
func (f Flavor) NewUnionBuilder() *UnionBuilder {
b := newUnionBuilder()
b.SetFlavor(f)
return b
}
// NewCTEBuilder creates a new CTE builder with flavor.
func (f Flavor) NewCTEBuilder() *CTEBuilder {
b := newCTEBuilder()
b.SetFlavor(f)
return b
}
// NewCTETableBuilder creates a new CTE table builder with flavor.
func (f Flavor) NewCTEQueryBuilder() *CTEQueryBuilder {
b := newCTEQueryBuilder()
b.SetFlavor(f)
return b
}
// Quote adds quote for name to make sure the name can be used safely
// as table name or field name.
//
// - For MySQL, use back quote (`) to quote name;
// - For PostgreSQL, SQL Server and SQLite, use double quote (") to quote name.
func (f Flavor) Quote(name string) string {
switch f {
case MySQL, ClickHouse:
return fmt.Sprintf("`%s`", name)
case PostgreSQL, SQLServer, SQLite, Presto, Oracle, Informix:
return fmt.Sprintf(`"%s"`, name)
case CQL:
return fmt.Sprintf("'%s'", name)
}
return name
}
// PrepareInsertIgnore prepares the insert builder to build insert ignore SQL statement based on the sql flavor
func (f Flavor) PrepareInsertIgnore(table string, ib *InsertBuilder) {
switch ib.args.Flavor {
case MySQL, Oracle:
ib.verb = "INSERT IGNORE"
case PostgreSQL:
// see https://www.postgresql.org/docs/current/sql-insert.html
ib.verb = "INSERT"
// add sql statement at the end after values, i.e. INSERT INTO ... ON CONFLICT DO NOTHING
ib.marker = insertMarkerAfterValues
ib.SQL("ON CONFLICT DO NOTHING")
case SQLite:
// see https://www.sqlite.org/lang_insert.html
ib.verb = "INSERT OR IGNORE"
case ClickHouse, CQL, SQLServer, Presto, Informix:
// All other databases do not support insert ignore
ib.verb = "INSERT"
default:
// panic if the db flavor is not supported
panic(fmt.Errorf("unsupported db flavor: %s", ib.args.Flavor.String()))
}
// Set the table and reset the marker right after insert into
ib.table = Escape(table)
ib.marker = insertMarkerAfterInsertInto
}