pgxtype-experiment2
Jack Christensen 2017-02-27 18:54:20 -06:00
parent d934f27362
commit 0f50ce3e83
2 changed files with 140 additions and 76 deletions

View File

@ -101,7 +101,9 @@ type UntypedTextArray struct {
}
func ParseUntypedTextArray(src string) (*UntypedTextArray, error) {
uta := &UntypedTextArray{}
uta := &UntypedTextArray{
Elements: []string{},
}
buf := bytes.NewBufferString(src)
@ -112,83 +114,80 @@ func ParseUntypedTextArray(src string) (*UntypedTextArray, error) {
return nil, fmt.Errorf("invalid array: %v", err)
}
var explicitBounds bool
// Array has explicit bounds
if r == '[' {
var explicitDimensions []ArrayDimension
// Array has explicit dimensions
if r == '[' {
// TODO - parse explicit dimensions
panic(explicitDimensions)
}
// Parse values
// Consume all initial opening brackets. This provides number of dimensions.
var implicitDimensions []ArrayDimension
if r != '{' {
return nil, fmt.Errorf("invalid array, expected '{': %v", err)
}
if !explicitBounds {
uta.Dimensions = append(uta.Dimensions, ArrayDimension{LowerBound: 1})
}
currentDimension := 0
for currentDimension >= 0 {
}
switch r {
case '(':
utr.LowerType = Exclusive
case '[':
utr.LowerType = Inclusive
default:
return nil, fmt.Errorf("missing lower bound, instead got: %v", string(r))
}
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("invalid lower value: %v", err)
}
buf.UnreadRune()
if r == ',' {
utr.LowerType = Unbounded
} else {
utr.Lower, err = rangeParseValue(buf)
for {
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("invalid lower value: %v", err)
return nil, fmt.Errorf("invalid array: %v", err)
}
if r == '{' {
implicitDimensions = append(implicitDimensions, ArrayDimension{LowerBound: 1})
} else {
buf.UnreadRune()
break
}
}
currentDim := len(implicitDimensions) - 1
counterDim := currentDim
elemCount := 0
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("missing range separator: %v", err)
}
if r != ',' {
return nil, fmt.Errorf("missing range separator: %v", r)
}
fmt.Println("-------", currentDim, buf.String())
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("invalid upper value: %v", err)
}
buf.UnreadRune()
if r == ')' || r == ']' {
utr.UpperType = Unbounded
} else {
utr.Upper, err = rangeParseValue(buf)
for {
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("invalid upper value: %v", err)
return nil, fmt.Errorf("invalid array: %v", err)
}
switch r {
case '{':
fmt.Println("{", buf.String())
if counterDim == currentDim {
elemCount++
}
currentDim++
case ',':
case '}':
fmt.Println("}", buf.String())
if counterDim == currentDim {
implicitDimensions[counterDim].Length = int32(elemCount)
elemCount = 0
}
currentDim--
default:
buf.UnreadRune()
fmt.Println("default", buf.String())
value, err := arrayParseValue(buf)
if err != nil {
return nil, fmt.Errorf("invalid array value: %v", err)
}
if counterDim == currentDim {
elemCount++
}
uta.Elements = append(uta.Elements, value)
}
if currentDim < 0 {
break
}
}
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("missing upper bound: %v", err)
}
switch r {
case ')':
utr.UpperType = Exclusive
case ']':
utr.UpperType = Inclusive
default:
return nil, fmt.Errorf("missing upper bound, instead got: %v", string(r))
}
skipWhitespace(buf)
@ -197,7 +196,16 @@ func ParseUntypedTextArray(src string) (*UntypedTextArray, error) {
return nil, fmt.Errorf("unexpected trailing data: %v", buf.String())
}
return utr, nil
if len(explicitDimensions) > 0 {
uta.Dimensions = explicitDimensions
} else {
uta.Dimensions = implicitDimensions
if len(uta.Dimensions) == 1 && uta.Dimensions[0].Length == 0 {
uta.Dimensions = []ArrayDimension{}
}
}
return uta, nil
}
func skipWhitespace(buf *bytes.Buffer) {
@ -211,13 +219,13 @@ func skipWhitespace(buf *bytes.Buffer) {
}
}
func rangeParseValue(buf *bytes.Buffer) (string, error) {
func arrayParseValue(buf *bytes.Buffer) (string, error) {
r, _, err := buf.ReadRune()
if err != nil {
return "", err
}
if r == '"' {
return rangeParseQuotedValue(buf)
return arrayParseQuotedValue(buf)
}
buf.UnreadRune()
@ -230,12 +238,7 @@ func rangeParseValue(buf *bytes.Buffer) (string, error) {
}
switch r {
case '\\':
r, _, err = buf.ReadRune()
if err != nil {
return "", err
}
case ',', '[', ']', '(', ')':
case ',', '}':
buf.UnreadRune()
return s.String(), nil
}
@ -244,7 +247,7 @@ func rangeParseValue(buf *bytes.Buffer) (string, error) {
}
}
func rangeParseQuotedValue(buf *bytes.Buffer) (string, error) {
func arrayParseQuotedValue(buf *bytes.Buffer) (string, error) {
s := &bytes.Buffer{}
for {
@ -264,10 +267,8 @@ func rangeParseQuotedValue(buf *bytes.Buffer) (string, error) {
if err != nil {
return "", err
}
if r != '"' {
buf.UnreadRune()
return s.String(), nil
}
buf.UnreadRune()
return s.String(), nil
}
s.WriteRune(r)
}

63
pgtype/array_test.go Normal file
View File

@ -0,0 +1,63 @@
package pgtype_test
import (
"reflect"
"testing"
"github.com/jackc/pgx/pgtype"
)
func TestParseUntypedTextArray(t *testing.T) {
tests := []struct {
source string
result pgtype.UntypedTextArray
}{
{
source: "{}",
result: pgtype.UntypedTextArray{
Elements: []string{},
Dimensions: []pgtype.ArrayDimension{},
},
},
{
source: "{1}",
result: pgtype.UntypedTextArray{
Elements: []string{"1"},
Dimensions: []pgtype.ArrayDimension{{Length: 1, LowerBound: 1}},
},
},
{
source: "{a,b}",
result: pgtype.UntypedTextArray{
Elements: []string{"a", "b"},
Dimensions: []pgtype.ArrayDimension{{Length: 2, LowerBound: 1}},
},
},
{
source: `{"NULL"}`,
result: pgtype.UntypedTextArray{
Elements: []string{"NULL"},
Dimensions: []pgtype.ArrayDimension{{Length: 1, LowerBound: 1}},
},
},
{
source: `{"He said, \"Hello.\""}`,
result: pgtype.UntypedTextArray{
Elements: []string{`He said, "Hello."`},
Dimensions: []pgtype.ArrayDimension{{Length: 1, LowerBound: 1}},
},
},
}
for i, tt := range tests {
r, err := pgtype.ParseUntypedTextArray(tt.source)
if err != nil {
t.Errorf("%d: %v", i, err)
continue
}
if !reflect.DeepEqual(*r, tt.result) {
t.Errorf("%d: expected %+v to be parsed to %+v, but it was %+v", i, tt.source, tt.result, *r)
}
}
}