Last active
July 11, 2016 11:38
-
-
Save pkieltyka/06b5f25295bf24d7a5de to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// PARSING ARRAYS | |
// SEE http://www.postgresql.org/docs/9.1/static/arrays.html#ARRAYS-IO | |
// Arrays are output within {} and a delimiter, which is a comma for most | |
// postgres types (; for box) | |
// | |
// Individual values are surrounded by quotes: | |
// The array output routine will put double quotes around element values if | |
// they are empty strings, contain curly braces, delimiter characters, | |
// double quotes, backslashes, or white space, or match the word NULL. | |
// Double quotes and backslashes embedded in element values will be | |
// backslash-escaped. For numeric data types it is safe to assume that double | |
// quotes will never appear, but for textual data types one should be prepared | |
// to cope with either the presence or absence of quotes. | |
// construct a regexp to extract values: | |
var ( | |
// unquoted array values must not contain: (" , \ { } whitespace NULL) | |
// and must be at least one char | |
unquotedChar = `[^",\\{}\s(NULL)]` | |
unquotedValue = fmt.Sprintf("(%s)+", unquotedChar) | |
// quoted array values are surrounded by double quotes, can be any | |
// character except " or \, which must be backslash escaped: | |
quotedChar = `[^"\\]|\\"|\\\\` | |
quotedValue = fmt.Sprintf("\"(%s)*\"", quotedChar) | |
// an array value may be either quoted or unquoted: | |
arrayValue = fmt.Sprintf("(?P<value>(%s|%s))", unquotedValue, quotedValue) | |
// Array values are separated with a comma IF there is more than one value: | |
arrayExp = regexp.MustCompile(fmt.Sprintf("((%s)(,)?)", arrayValue)) | |
) | |
type StringArray []string | |
func (a *StringArray) Scan(src interface{}) error { | |
asBytes, ok := src.([]byte) | |
if !ok { | |
return errors.New("Scan source was not []bytes") | |
} | |
asString := string(asBytes) | |
results := make([]string, 0) | |
matches := arrayExp.FindAllStringSubmatch(asString, -1) | |
for _, match := range matches { | |
s := match[0] | |
// the string _might_ be wrapped in quotes, so trim them: | |
s = strings.Trim(s, "\"") | |
results = append(results, s) | |
} | |
*a = StringArray(results) | |
return nil | |
} | |
func (a StringArray) Value() (driver.Value, error) { | |
if len(a) == 0 { | |
return nil, nil | |
} | |
var buffer bytes.Buffer | |
buffer.WriteString("{") | |
last := len(a) - 1 | |
for i, val := range a { | |
buffer.WriteString(strconv.Quote(val)) | |
if i != last { | |
buffer.WriteString(",") | |
} | |
} | |
buffer.WriteString("}") | |
return string(buffer.Bytes()), nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment