dialect/sql/sqljson: quote non-identifiers (#2910)

* dialect/sql: fixed invalid json path quote

* fix: fixed empty string

* fix: fixed lint issue

* Apply suggestions from code review

Co-authored-by: Ariel Mashraki <7413593+a8m@users.noreply.github.com>

* fix: added test to new case

Co-authored-by: Ariel Mashraki <7413593+a8m@users.noreply.github.com>
This commit is contained in:
Giau. Tran Minh
2022-09-07 18:49:11 +07:00
committed by GitHub
parent 1773fc465e
commit 2cdb627c0d
2 changed files with 58 additions and 28 deletions

View File

@@ -430,15 +430,18 @@ func (p *PathOptions) mysqlFunc(fn string, b *sql.Builder) {
// mysqlPath writes the JSON path in MySQL (or SQLite) format.
func (p *PathOptions) mysqlPath(b *sql.Builder) {
b.WriteString(`"$`)
b.WriteString(`'$`)
for _, p := range p.Path {
if _, ok := isJSONIdx(p); ok {
switch _, isIndex := isJSONIdx(p); {
case isIndex:
b.WriteString(p)
} else {
case p == "*" || isQuoted(p) || isIdentifier(p):
b.WriteString("." + p)
default:
b.WriteString(`."` + p + `"`)
}
}
b.WriteByte('"')
b.WriteByte('\'')
}
// pgPath writes the JSON path in Postgres format `"a"->'b'->>'c'`.
@@ -529,6 +532,25 @@ func normalizePG(b *sql.Builder, arg any, opts []Option) []Option {
return append(base, opts...)
}
func isIdentifier(name string) bool {
if name == "" {
return false
}
for i, c := range name {
if !unicode.IsLetter(c) && c != '_' && (i == 0 || !unicode.IsDigit(c)) {
return false
}
}
return true
}
func isQuoted(s string) bool {
if s == "" {
return false
}
return s[0] == '"' && s[len(s)-1] == '"'
}
// isJSONIdx reports whether the string represents a JSON index.
func isJSONIdx(s string) (string, bool) {
if len(s) > 2 && s[0] == '[' && s[len(s)-1] == ']' && isNumber(s[1:len(s)-1]) {