GoToSocial/vendor/github.com/uptrace/bun/dialect/pgdialect/hstore_parser.go

143 lines
2.0 KiB
Go

package pgdialect
import (
"bytes"
"fmt"
)
type hstoreParser struct {
*streamParser
err error
}
func newHStoreParser(b []byte) *hstoreParser {
p := &hstoreParser{
streamParser: newStreamParser(b, 0),
}
if len(b) < 6 || b[0] != '"' {
p.err = fmt.Errorf("bun: can't parse hstore: %q", b)
}
return p
}
func (p *hstoreParser) NextKey() (string, error) {
if p.err != nil {
return "", p.err
}
err := p.skipByte('"')
if err != nil {
return "", err
}
key, err := p.readSubstring()
if err != nil {
return "", err
}
const separator = "=>"
for i := range separator {
err = p.skipByte(separator[i])
if err != nil {
return "", err
}
}
return string(key), nil
}
func (p *hstoreParser) NextValue() (string, error) {
if p.err != nil {
return "", p.err
}
c, err := p.readByte()
if err != nil {
return "", err
}
switch c {
case '"':
value, err := p.readSubstring()
if err != nil {
return "", err
}
if p.peek() == ',' {
p.skipNext()
}
if p.peek() == ' ' {
p.skipNext()
}
return string(value), nil
default:
value := p.readSimple()
if bytes.Equal(value, []byte("NULL")) {
value = nil
}
if p.peek() == ',' {
p.skipNext()
}
return string(value), nil
}
}
func (p *hstoreParser) readSimple() []byte {
p.unreadByte()
if i := bytes.IndexByte(p.b[p.i:], ','); i >= 0 {
b := p.b[p.i : p.i+i]
p.i += i
return b
}
b := p.b[p.i:len(p.b)]
p.i = len(p.b)
return b
}
func (p *hstoreParser) readSubstring() ([]byte, error) {
c, err := p.readByte()
if err != nil {
return nil, err
}
p.buf = p.buf[:0]
for {
if c == '"' {
break
}
next, err := p.readByte()
if err != nil {
return nil, err
}
if c == '\\' {
switch next {
case '\\', '"':
p.buf = append(p.buf, next)
c, err = p.readByte()
if err != nil {
return nil, err
}
default:
p.buf = append(p.buf, '\\')
c = next
}
continue
}
p.buf = append(p.buf, c)
c = next
}
return p.buf, nil
}