Skip to content

Commit c25b4f2

Browse files
authored
Merge pull request #99 from huandu/feature-presto
fix #98 Add new flavor Presto
2 parents 71a8512 + e2c1687 commit c25b4f2

File tree

7 files changed

+79
-9
lines changed

7 files changed

+79
-9
lines changed

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ To learn how to use builders, check out [examples on GoDoc](https://pkg.go.dev/g
114114

115115
SQL syntax and parameter marks vary in different systems. In this package, we introduce a concept called "flavor" to smooth out these difference.
116116

117-
Right now, MySQL, PostgreSQL, SQLServer, SQLite, CQL and ClickHouse are defined in flavor list. Feel free to open issue or send pull request if anyone asks for a new flavor.
117+
Right now, `MySQL`, `PostgreSQL`, `SQLServer`, `SQLite`, `CQL`, `ClickHouse` and `Presto` are defined in flavor list. Feel free to open issue or send pull request if anyone asks for a new flavor.
118118

119119
By default, all builders uses `DefaultFlavor` to build SQL. The default value is `MySQL`.
120120

@@ -124,8 +124,6 @@ We can wrap any `Builder` with a default flavor through `WithFlavor`.
124124

125125
To be more verbose, we can use `PostgreSQL.NewSelectBuilder()` to create a `SelectBuilder` with the `PostgreSQL` flavor. All builders can be created in this way.
126126

127-
Right now, there are five flavors, `MySQL`, `PostgreSQL`, `SQLServer`, `SQLite`, and `CQL`. Open new issue to me to ask for a new flavor if you find it necessary.
128-
129127
### Using `Struct` as a light weight ORM
130128

131129
`Struct` stores type information and struct fields of a struct. It's a factory of builders. We can use `Struct` methods to create initialized SELECT/INSERT/UPDATE/DELETE builders to work with the struct. It can help us to save time and avoid human-error on writing column names.

args.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ func (args *Args) compileArg(buf *bytes.Buffer, flavor Flavor, values []interfac
233233
}
234234
default:
235235
switch flavor {
236-
case MySQL, SQLite, CQL, ClickHouse:
236+
case MySQL, SQLite, CQL, ClickHouse, Presto:
237237
buf.WriteRune('?')
238238
case PostgreSQL:
239239
fmt.Fprintf(buf, "$%d", len(values)+1)

flavor.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const (
1818
SQLServer
1919
CQL
2020
ClickHouse
21+
Presto
2122
)
2223

2324
var (
@@ -55,6 +56,8 @@ func (f Flavor) String() string {
5556
return "CQL"
5657
case ClickHouse:
5758
return "ClickHouse"
59+
case Presto:
60+
return "Presto"
5861
}
5962

6063
return "<invalid>"
@@ -79,6 +82,8 @@ func (f Flavor) Interpolate(sql string, args []interface{}) (string, error) {
7982
return cqlInterpolate(sql, args...)
8083
case ClickHouse:
8184
return clickhouseInterpolate(sql, args...)
85+
case Presto:
86+
return prestoInterpolate(sql, args...)
8287
}
8388

8489
return "", ErrInterpolateNotImplemented
@@ -135,7 +140,7 @@ func (f Flavor) Quote(name string) string {
135140
switch f {
136141
case MySQL, ClickHouse:
137142
return fmt.Sprintf("`%s`", name)
138-
case PostgreSQL, SQLServer, SQLite:
143+
case PostgreSQL, SQLServer, SQLite, Presto:
139144
return fmt.Sprintf(`"%s"`, name)
140145
case CQL:
141146
return fmt.Sprintf("'%s'", name)
@@ -149,18 +154,22 @@ func (f Flavor) PrepareInsertIgnore(table string, ib *InsertBuilder) {
149154
switch ib.args.Flavor {
150155
case MySQL:
151156
ib.verb = "INSERT IGNORE"
157+
152158
case PostgreSQL:
153159
// see https://www.postgresql.org/docs/current/sql-insert.html
154160
ib.verb = "INSERT"
155161
// add sql statement at the end after values, i.e. INSERT INTO ... ON CONFLICT DO NOTHING
156162
ib.marker = insertMarkerAfterValues
157163
ib.SQL("ON CONFLICT DO NOTHING")
164+
158165
case SQLite:
159166
// see https://www.sqlite.org/lang_insert.html
160167
ib.verb = "INSERT OR IGNORE"
161-
case ClickHouse:
162-
// see https://clickhouse.tech/docs/en/sql-reference/statements/insert-into/
168+
169+
case ClickHouse, CQL, SQLServer, Presto:
170+
// All other databases do not support insert ignore
163171
ib.verb = "INSERT"
172+
164173
default:
165174
// panic if the db flavor is not supported
166175
panic(fmt.Errorf("unsupported db flavor: %s", ib.args.Flavor.String()))

interpolate.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,10 @@ func clickhouseInterpolate(query string, args ...interface{}) (string, error) {
395395
return mysqlLikeInterpolate(ClickHouse, query, args...)
396396
}
397397

398+
func prestoInterpolate(query string, args ...interface{}) (string, error) {
399+
return mysqlLikeInterpolate(Presto, query, args...)
400+
}
401+
398402
func encodeValue(buf []byte, arg interface{}, flavor Flavor) ([]byte, error) {
399403
switch v := arg.(type) {
400404
case nil:
@@ -436,6 +440,9 @@ func encodeValue(buf []byte, arg interface{}, flavor Flavor) ([]byte, error) {
436440

437441
case ClickHouse:
438442
buf = append(buf, v.Format("2006-01-02 15:04:05.999999")...)
443+
444+
case Presto:
445+
buf = append(buf, v.Format("2006-01-02 15:04:05.000")...)
439446
}
440447

441448
buf = append(buf, '\'')
@@ -541,6 +548,11 @@ func encodeValue(buf []byte, arg interface{}, flavor Flavor) ([]byte, error) {
541548
buf = append(buf, "unhex('"...)
542549
buf = appendHex(buf, data)
543550
buf = append(buf, "')"...)
551+
552+
case Presto:
553+
buf = append(buf, "from_hex('"...)
554+
buf = appendHex(buf, data)
555+
buf = append(buf, "')"...)
544556
}
545557

546558
default:

interpolate_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,51 @@ func TestFlavorInterpolate(t *testing.T) {
238238
"SELECT ?", []interface{}{errorValuer(1)},
239239
"", ErrErrorValuer,
240240
},
241+
{
242+
Presto,
243+
"SELECT * FROM a WHERE name = ? AND state IN (?, ?, ?, ?, ?)", []interface{}{"I'm fine", 42, int8(8), int16(-16), int32(32), int64(64)},
244+
"SELECT * FROM a WHERE name = 'I\\'m fine' AND state IN (42, 8, -16, 32, 64)", nil,
245+
},
246+
{
247+
Presto,
248+
"SELECT * FROM `a?` WHERE name = \"?\" AND state IN (?, '?', ?, ?, ?, ?, ?)", []interface{}{"\r\n\b\t\x1a\x00\\\"'", uint(42), uint8(8), uint16(16), uint32(32), uint64(64), "useless"},
249+
"SELECT * FROM `a?` WHERE name = \"?\" AND state IN ('\\r\\n\\b\\t\\Z\\0\\\\\\\"\\'', '?', 42, 8, 16, 32, 64)", nil,
250+
},
251+
{
252+
Presto,
253+
"SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?", []interface{}{true, false, float32(1.234567), 9.87654321, []byte(nil), []byte("I'm bytes"), dt, time.Time{}, nil},
254+
"SELECT TRUE, FALSE, 1.234567, 9.87654321, NULL, from_hex('49276D206279746573'), '2019-04-24 12:23:34.123', '0000-00-00', NULL", nil,
255+
},
256+
{
257+
Presto,
258+
"SELECT '\\'?', \"\\\"?\", `\\`?`, \\?", []interface{}{MySQL},
259+
"SELECT '\\'?', \"\\\"?\", `\\`?`, \\'MySQL'", nil,
260+
},
261+
{
262+
Presto,
263+
"SELECT ?", []interface{}{byteArr},
264+
"SELECT from_hex('666F6F')", nil,
265+
},
266+
{
267+
Presto,
268+
"SELECT ?", nil,
269+
"", ErrInterpolateMissingArgs,
270+
},
271+
{
272+
Presto,
273+
"SELECT ?", []interface{}{complex(1, 2)},
274+
"", ErrInterpolateUnsupportedArgs,
275+
},
276+
{
277+
Presto,
278+
"SELECT ?", []interface{}{[]complex128{complex(1, 2)}},
279+
"", ErrInterpolateUnsupportedArgs,
280+
},
281+
{
282+
Presto,
283+
"SELECT ?", []interface{}{errorValuer(1)},
284+
"", ErrErrorValuer,
285+
},
241286
}
242287

243288
for idx, c := range cases {

select.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
317317
buf.WriteString(" LIMIT ")
318318
buf.WriteString(strconv.Itoa(sb.limit))
319319
}
320-
case PostgreSQL:
320+
case PostgreSQL, Presto:
321321
if sb.limit >= 0 {
322322
buf.WriteString(" LIMIT ")
323323
buf.WriteString(strconv.Itoa(sb.limit))

select_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func ExampleSelectBuilder_join() {
112112
}
113113

114114
func ExampleSelectBuilder_limit_offset() {
115-
flavors := []Flavor{MySQL, PostgreSQL, SQLite, SQLServer, CQL, ClickHouse}
115+
flavors := []Flavor{MySQL, PostgreSQL, SQLite, SQLServer, CQL, ClickHouse, Presto}
116116
results := make([][]string, len(flavors))
117117
sb := NewSelectBuilder()
118118
saveResults := func() {
@@ -203,6 +203,12 @@ func ExampleSelectBuilder_limit_offset() {
203203
// #2: SELECT * FROM user
204204
// #3: SELECT * FROM user LIMIT 1 OFFSET 0
205205
// #4: SELECT * FROM user LIMIT 1
206+
//
207+
// Presto
208+
// #1: SELECT * FROM user
209+
// #2: SELECT * FROM user OFFSET 0
210+
// #3: SELECT * FROM user LIMIT 1 OFFSET 0
211+
// #4: SELECT * FROM user LIMIT 1
206212
}
207213

208214
func ExampleSelectBuilder_ForUpdate() {

0 commit comments

Comments
 (0)