storage: expose SplitWords in a separate package
Change-Id: I371274fad0b6ef8d79a1c5581917c847c3e94830
Reviewed-on: https://go-review.googlesource.com/35948
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/storage/db/db.go b/storage/db/db.go
index c0aef58..5db5e0a 100644
--- a/storage/db/db.go
+++ b/storage/db/db.go
@@ -20,6 +20,7 @@
"golang.org/x/net/context"
"golang.org/x/perf/storage/benchfmt"
+ "golang.org/x/perf/storage/query"
)
// TODO(quentin): Add Context to every function when App Engine supports Go >=1.8.
@@ -365,7 +366,7 @@
// key>value - value greater than (useful for dates)
// key<value - value less than (also useful for dates)
func (db *DB) Query(q string) *Query {
- qparts := splitQueryWords(q)
+ qparts := query.SplitWords(q)
var args []interface{}
query := "SELECT r.Content FROM "
@@ -414,48 +415,6 @@
return &Query{rows: rows}
}
-// splitQueryWords splits q into words using shell syntax (whitespace
-// can be escaped with double quotes or with a backslash).
-func splitQueryWords(q string) []string {
- var words []string
- word := make([]byte, len(q))
- w := 0
- quoting := false
- for r := 0; r < len(q); r++ {
- switch c := q[r]; {
- case c == '"' && quoting:
- quoting = false
- case quoting:
- if c == '\\' {
- r++
- }
- if r < len(q) {
- word[w] = q[r]
- w++
- }
- case c == '"':
- quoting = true
- case c == ' ', c == '\t':
- if w > 0 {
- words = append(words, string(word[:w]))
- }
- w = 0
- case c == '\\':
- r++
- fallthrough
- default:
- if r < len(q) {
- word[w] = q[r]
- w++
- }
- }
- }
- if w > 0 {
- words = append(words, string(word[:w]))
- }
- return words
-}
-
// Query is the result of a query.
// Use Next to advance through the rows, making sure to call Close when done:
//
diff --git a/storage/db/db_test.go b/storage/db/db_test.go
index 046622e..97c9382 100644
--- a/storage/db/db_test.go
+++ b/storage/db/db_test.go
@@ -11,7 +11,6 @@
"io/ioutil"
"os"
"os/exec"
- "reflect"
"strings"
"testing"
"time"
@@ -23,24 +22,6 @@
// Most of the db package is tested via the end-to-end-tests in perf/storage/app.
-func TestSplitQueryWords(t *testing.T) {
- for _, test := range []struct {
- q string
- want []string
- }{
- {"hello world", []string{"hello", "world"}},
- {"hello\\ world", []string{"hello world"}},
- {`"key:value two" and\ more`, []string{"key:value two", "and more"}},
- {`one" two"\ three four`, []string{"one two three", "four"}},
- {`"4'7\""`, []string{`4'7"`}},
- } {
- have := SplitQueryWords(test.q)
- if !reflect.DeepEqual(have, test.want) {
- t.Errorf("splitQueryWords(%q) = %+v, want %+v", test.q, have, test.want)
- }
- }
-}
-
// TestUploadIDs verifies that NewUpload generates the correct sequence of upload IDs.
func TestUploadIDs(t *testing.T) {
ctx := context.Background()
diff --git a/storage/db/export_test.go b/storage/db/export_test.go
index 5f465f0..da163da 100644
--- a/storage/db/export_test.go
+++ b/storage/db/export_test.go
@@ -9,8 +9,6 @@
"time"
)
-var SplitQueryWords = splitQueryWords
-
func DBSQL(db *DB) *sql.DB {
return db.sql
}
diff --git a/storage/query/query.go b/storage/query/query.go
new file mode 100644
index 0000000..9b62b5a
--- /dev/null
+++ b/storage/query/query.go
@@ -0,0 +1,48 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package query provides tools for parsing a query.
+package query
+
+// SplitWords splits q into words using shell syntax (whitespace
+// can be escaped with double quotes or with a backslash).
+func SplitWords(q string) []string {
+ var words []string
+ word := make([]byte, len(q))
+ w := 0
+ quoting := false
+ for r := 0; r < len(q); r++ {
+ switch c := q[r]; {
+ case c == '"' && quoting:
+ quoting = false
+ case quoting:
+ if c == '\\' {
+ r++
+ }
+ if r < len(q) {
+ word[w] = q[r]
+ w++
+ }
+ case c == '"':
+ quoting = true
+ case c == ' ', c == '\t':
+ if w > 0 {
+ words = append(words, string(word[:w]))
+ }
+ w = 0
+ case c == '\\':
+ r++
+ fallthrough
+ default:
+ if r < len(q) {
+ word[w] = q[r]
+ w++
+ }
+ }
+ }
+ if w > 0 {
+ words = append(words, string(word[:w]))
+ }
+ return words
+}
diff --git a/storage/query/query_test.go b/storage/query/query_test.go
new file mode 100644
index 0000000..91bcaea
--- /dev/null
+++ b/storage/query/query_test.go
@@ -0,0 +1,28 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package query
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestSplitQueryWords(t *testing.T) {
+ for _, test := range []struct {
+ q string
+ want []string
+ }{
+ {"hello world", []string{"hello", "world"}},
+ {"hello\\ world", []string{"hello world"}},
+ {`"key:value two" and\ more`, []string{"key:value two", "and more"}},
+ {`one" two"\ three four`, []string{"one two three", "four"}},
+ {`"4'7\""`, []string{`4'7"`}},
+ } {
+ have := SplitWords(test.q)
+ if !reflect.DeepEqual(have, test.want) {
+ t.Errorf("splitQueryWords(%q) = %+v, want %+v", test.q, have, test.want)
+ }
+ }
+}