70 lines
1.6 KiB
Go
70 lines
1.6 KiB
Go
package store
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Dialect captures the small syntactic differences between SQL backends.
|
|
// All queries are written with ? placeholders; Rebind rewrites them as
|
|
// needed for the target driver. Semantic differences (e.g., RETURNING
|
|
// support) are not the Dialect's concern — they belong in separate Store
|
|
// implementations.
|
|
type Dialect interface {
|
|
Rebind(query string) string
|
|
}
|
|
|
|
// SQLiteDialect leaves queries unchanged; database/sql + the SQLite driver
|
|
// already accept ? placeholders.
|
|
type SQLiteDialect struct{}
|
|
|
|
func (SQLiteDialect) Rebind(query string) string { return query }
|
|
|
|
// PostgresDialect rewrites ? placeholders into $1, $2, ... while leaving
|
|
// any ? characters that appear inside single-quoted string literals or
|
|
// double-quoted identifiers untouched.
|
|
type PostgresDialect struct{}
|
|
|
|
func (PostgresDialect) Rebind(query string) string {
|
|
var b strings.Builder
|
|
b.Grow(len(query) + 8)
|
|
|
|
n := 0
|
|
i := 0
|
|
for i < len(query) {
|
|
c := query[i]
|
|
switch c {
|
|
case '\'', '"':
|
|
// Copy the entire quoted span verbatim, handling doubled-quote escapes.
|
|
quote := c
|
|
b.WriteByte(c)
|
|
i++
|
|
for i < len(query) {
|
|
if query[i] == quote {
|
|
if i+1 < len(query) && query[i+1] == quote {
|
|
// Escaped quote: '' or "". Copy both bytes and continue.
|
|
b.WriteByte(quote)
|
|
b.WriteByte(quote)
|
|
i += 2
|
|
continue
|
|
}
|
|
b.WriteByte(quote)
|
|
i++
|
|
break
|
|
}
|
|
b.WriteByte(query[i])
|
|
i++
|
|
}
|
|
case '?':
|
|
n++
|
|
b.WriteByte('$')
|
|
b.WriteString(strconv.Itoa(n))
|
|
i++
|
|
default:
|
|
b.WriteByte(c)
|
|
i++
|
|
}
|
|
}
|
|
|
|
return b.String()
|
|
}
|