pqarrays

Paddy 2016-02-26 Parent:ce9c92fc81ab

2:9a415db0346a Go to Latest

pqarrays/array.go

Fix whitespace lexing/parsing. Our consumeWhitespace method had a bug where it wouldn't emit the whitespace token, meaning we weren't actually skipping the whitespace. Oops. While in there, I removed an outdated TODO (we already supplied a default state). I updated the lexing of unquoted strings to take into account the rules about spaces and unquoted strings; basically, spaces before or after are ignored as whitespace, spaces in the middle ocunt, and empty strings are not allowed. I removed an extra case when detecting what to do when lexing an unquoted string; we already consumed all the whitespace, so the next character shouldn't be whitespace, so no need to test for it. We need to consume whitespace before we start lexing the separator character. I updated the token debugging to be a bit more useful, by defining a String() method on the token type itself, so it'll expose both the type and the value. This makes unexpected errors easier to deal with, and is used in all the errors raised by the parser now. I added a bunch of whitespace tests for lexing and parsing.

History
1 package pqarrays
3 import (
4 "database/sql/driver"
5 "errors"
6 "strconv"
7 "strings"
8 )
10 var (
11 // ErrUnexpectedValueType is returned when the passed value is not a string or []byte.
12 ErrUnexpectedValueType = errors.New("expected value to be a string or []byte")
13 )
15 // StringArray represents a Postgres array as a []string.
16 type StringArray []string
18 // Value implements the Valuer interface for StringArray, allowing it to be transparently
19 // stored in Postgres databases using the database/sql package.
20 func (s StringArray) Value() (driver.Value, error) {
21 output := make([]string, 0, len(s))
22 for _, item := range s {
23 item = strconv.Quote(item)
24 item = strings.Replace(item, "'", "\\'", -1)
25 output = append(output, item)
26 }
27 return []byte(`{` + strings.Join(output, ",") + `}`), nil
28 }
30 // Scan implements the Scanner interface for StringArray, allowing it to be transparently
31 // retrieved from Postgres databases using the database/sql package. It expects `value` to
32 // be a string or []byte, and throws ErrUnexpectedValueType when any other type is encountered.
33 func (s *StringArray) Scan(value interface{}) error {
34 *s = (*s)[:0]
35 var input string
36 if _, ok := value.(string); ok {
37 input = value.(string)
38 } else if _, ok := value.([]byte); ok {
39 input = string(value.([]byte))
40 } else {
41 return ErrUnexpectedValueType
42 }
43 l := lex(input)
44 parsed, err := parse(l)
45 if err != nil {
46 return err
47 }
48 for _, item := range parsed {
49 if item == nil {
50 continue
51 }
52 *s = append(*s, *item)
53 }
54 return nil
55 }