Make query/... interfaces more idiomatic

Also revert the data type returned by queries to interface{} (the change
made sense at the time).
This commit is contained in:
kortschak 2015-02-10 10:06:57 +10:30
parent ad7649806b
commit 21c2d75d07
11 changed files with 304 additions and 299 deletions

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,7 @@ import (
"io" "io"
"os" "os"
"os/signal" "os/signal"
"strconv"
"strings" "strings"
"time" "time"
@ -53,9 +54,9 @@ func Run(query string, ses query.Session) {
}() }()
fmt.Printf("\n") fmt.Printf("\n")
c := make(chan interface{}, 5) c := make(chan interface{}, 5)
go ses.ExecInput(query, c, 100) go ses.Execute(query, c, 100)
for res := range c { for res := range c {
fmt.Print(ses.ToText(res)) fmt.Print(ses.Format(res))
nResults++ nResults++
} }
if nResults > 0 { if nResults > 0 {
@ -122,8 +123,22 @@ func Repl(h *graph.Handle, queryLanguage string, cfg *config.Config) error {
switch cmd { switch cmd {
case ":debug": case ":debug":
ses.ToggleDebug() args = strings.TrimSpace(args)
fmt.Println("Debug Toggled") var debug bool
switch args {
case "t":
debug = true
case "f":
// Do nothing.
default:
debug, err = strconv.ParseBool(args)
if err != nil {
fmt.Printf("Error: cannot parse %q as a valid boolean - acceptable values: 't'|'true' or 'f'|'false'\n", args)
continue
}
}
ses.Debug(debug)
fmt.Printf("Debug set to %t\n", debug)
continue continue
case ":a": case ":a":
@ -155,7 +170,7 @@ func Repl(h *graph.Handle, queryLanguage string, cfg *config.Config) error {
code += line code += line
result, err := ses.InputParses(code) result, err := ses.Parse(code)
switch result { switch result {
case query.Parsed: case query.Parsed:
Run(code, ses) Run(code, ses)

View file

@ -30,9 +30,9 @@ var testSplitLines = []struct {
expectedArguments: " arg1 arg2 arg3 .", expectedArguments: " arg1 arg2 arg3 .",
}, },
{ {
line: ":debug", line: ":debug t",
expectedCommand: ":debug", expectedCommand: ":debug",
// expectedArguments is nil expectedArguments: " t",
}, },
{ {
line: "", line: "",

View file

@ -49,21 +49,19 @@ func WrapResult(result interface{}) ([]byte, error) {
func Run(q string, ses query.HTTP) (interface{}, error) { func Run(q string, ses query.HTTP) (interface{}, error) {
c := make(chan interface{}, 5) c := make(chan interface{}, 5)
go ses.ExecInput(q, c, 100) go ses.Execute(q, c, 100)
for res := range c { for res := range c {
ses.BuildJSON(res) ses.Collate(res)
} }
return ses.GetJSON() return ses.Results()
} }
func GetQueryShape(q string, ses query.HTTP) ([]byte, error) { func GetQueryShape(q string, ses query.HTTP) ([]byte, error) {
c := make(chan map[string]interface{}, 5) s, err := ses.ShapeOf(q)
go ses.GetQuery(q, c) if err != nil {
var data map[string]interface{} return nil, err
for res := range c {
data = res
} }
return json.Marshal(data) return json.Marshal(s)
} }
// TODO(barakmich): Turn this into proper middleware. // TODO(barakmich): Turn this into proper middleware.
@ -82,7 +80,7 @@ func (api *API) ServeV1Query(w http.ResponseWriter, r *http.Request, params http
return jsonResponse(w, 400, err) return jsonResponse(w, 400, err)
} }
code := string(bodyBytes) code := string(bodyBytes)
result, err := ses.InputParses(code) result, err := ses.Parse(code)
switch result { switch result {
case query.Parsed: case query.Parsed:
var output interface{} var output interface{}
@ -127,7 +125,7 @@ func (api *API) ServeV1Shape(w http.ResponseWriter, r *http.Request, params http
return jsonResponse(w, 400, err) return jsonResponse(w, 400, err)
} }
code := string(bodyBytes) code := string(bodyBytes)
result, err := ses.InputParses(code) result, err := ses.Parse(code)
switch result { switch result {
case query.Parsed: case query.Parsed:
var output []byte var output []byte

View file

@ -265,7 +265,7 @@ var testQueries = []struct {
func runQueryGetTag(g []quad.Quad, query string, tag string) []string { func runQueryGetTag(g []quad.Quad, query string, tag string) []string {
js := makeTestSession(g) js := makeTestSession(g)
c := make(chan interface{}, 5) c := make(chan interface{}, 5)
js.ExecInput(query, c, -1) js.Execute(query, c, -1)
var results []string var results []string
for res := range c { for res := range c {
@ -318,7 +318,7 @@ func TestIssue160(t *testing.T) {
ses := makeTestSession(issue160TestGraph) ses := makeTestSession(issue160TestGraph)
c := make(chan interface{}, 5) c := make(chan interface{}, 5)
go ses.ExecInput(query, c, 100) go ses.Execute(query, c, 100)
var got []string var got []string
for res := range c { for res := range c {
func() { func() {
@ -327,7 +327,7 @@ func TestIssue160(t *testing.T) {
t.Errorf("Unexpected panic: %v", r) t.Errorf("Unexpected panic: %v", r)
} }
}() }()
got = append(got, ses.ToText(res)) got = append(got, ses.Format(res))
}() }()
} }
sort.Strings(got) sort.Strings(got)

View file

@ -65,19 +65,21 @@ type Result struct {
actualResults map[string]graph.Value actualResults map[string]graph.Value
} }
func (s *Session) ToggleDebug() { func (s *Session) Debug(ok bool) {
s.debug = !s.debug s.debug = ok
} }
func (s *Session) GetQuery(input string, out chan map[string]interface{}) { func (s *Session) ShapeOf(query string) (interface{}, error) {
defer close(out) // TODO(kortschak) It would be nice to be able
// to return an error for bad queries here.
s.wk.shape = make(map[string]interface{}) s.wk.shape = make(map[string]interface{})
s.wk.env.Run(input) s.wk.env.Run(query)
out <- s.wk.shape out := s.wk.shape
s.wk.shape = nil s.wk.shape = nil
return out, nil
} }
func (s *Session) InputParses(input string) (query.ParseResult, error) { func (s *Session) Parse(input string) (query.ParseResult, error) {
script, err := s.wk.env.Compile("", input) script, err := s.wk.env.Compile("", input)
if err != nil { if err != nil {
return query.ParseFail, err return query.ParseFail, err
@ -130,7 +132,7 @@ func (s *Session) runUnsafe(input interface{}) (otto.Value, error) {
return env.Run(input) return env.Run(input)
} }
func (s *Session) ExecInput(input string, out chan interface{}, _ int) { func (s *Session) Execute(input string, out chan interface{}, _ int) {
defer close(out) defer close(out)
s.err = nil s.err = nil
s.wk.results = out s.wk.results = out
@ -153,7 +155,7 @@ func (s *Session) ExecInput(input string, out chan interface{}, _ int) {
s.wk.Unlock() s.wk.Unlock()
} }
func (s *Session) ToText(result interface{}) string { func (s *Session) Format(result interface{}) string {
data := result.(*Result) data := result.(*Result)
if data.metaresult { if data.metaresult {
if data.err != nil { if data.err != nil {
@ -212,7 +214,7 @@ func (s *Session) ToText(result interface{}) string {
} }
// Web stuff // Web stuff
func (s *Session) BuildJSON(result interface{}) { func (s *Session) Collate(result interface{}) {
data := result.(*Result) data := result.(*Result)
if !data.metaresult { if !data.metaresult {
if data.val == nil { if data.val == nil {
@ -246,8 +248,8 @@ func (s *Session) BuildJSON(result interface{}) {
} }
} }
func (s *Session) GetJSON() ([]interface{}, error) { func (s *Session) Results() (interface{}, error) {
defer s.ClearJSON() defer s.Clear()
if s.err != nil { if s.err != nil {
return nil, s.err return nil, s.err
} }
@ -259,6 +261,6 @@ func (s *Session) GetJSON() ([]interface{}, error) {
} }
} }
func (s *Session) ClearJSON() { func (s *Session) Clear() {
s.dataOutput = nil s.dataOutput = nil
} }

View file

@ -170,11 +170,11 @@ var testQueries = []struct {
func runQuery(g []quad.Quad, query string) interface{} { func runQuery(g []quad.Quad, query string) interface{} {
s := makeTestSession(g) s := makeTestSession(g)
c := make(chan interface{}, 5) c := make(chan interface{}, 5)
go s.ExecInput(query, c, -1) go s.Execute(query, c, -1)
for result := range c { for result := range c {
s.BuildJSON(result) s.Collate(result)
} }
result, _ := s.GetJSON() result, _ := s.Results()
return result return result
} }

View file

@ -108,8 +108,6 @@ func (p Path) ToResultPathFromMap(resultMap map[Path]string) ResultPath {
func NewQuery(ses *Session) *Query { func NewQuery(ses *Session) *Query {
var q Query var q Query
q.ses = ses q.ses = ses
q.results = make([]interface{}, 0)
q.resultOrder = make([]string, 0)
q.err = nil q.err = nil
return &q return &q
} }

View file

@ -38,16 +38,15 @@ func NewSession(qs graph.QuadStore) *Session {
return &m return &m
} }
func (s *Session) ToggleDebug() { func (s *Session) Debug(ok bool) {
s.debug = !s.debug s.debug = ok
} }
func (s *Session) GetQuery(input string, out chan map[string]interface{}) { func (s *Session) ShapeOf(query string) (interface{}, error) {
defer close(out)
var mqlQuery interface{} var mqlQuery interface{}
err := json.Unmarshal([]byte(input), &mqlQuery) err := json.Unmarshal([]byte(query), &mqlQuery)
if err != nil { if err != nil {
return return nil, err
} }
s.currentQuery = NewQuery(s) s.currentQuery = NewQuery(s)
s.currentQuery.BuildIteratorTree(mqlQuery) s.currentQuery.BuildIteratorTree(mqlQuery)
@ -59,10 +58,10 @@ func (s *Session) GetQuery(input string, out chan map[string]interface{}) {
nodes = append(nodes, n) nodes = append(nodes, n)
} }
output["nodes"] = nodes output["nodes"] = nodes
out <- output return output, nil
} }
func (s *Session) InputParses(input string) (query.ParseResult, error) { func (s *Session) Parse(input string) (query.ParseResult, error) {
var x interface{} var x interface{}
err := json.Unmarshal([]byte(input), &x) err := json.Unmarshal([]byte(input), &x)
if err != nil { if err != nil {
@ -71,7 +70,7 @@ func (s *Session) InputParses(input string) (query.ParseResult, error) {
return query.Parsed, nil return query.Parsed, nil
} }
func (s *Session) ExecInput(input string, c chan interface{}, _ int) { func (s *Session) Execute(input string, c chan interface{}, _ int) {
defer close(c) defer close(c)
var mqlQuery interface{} var mqlQuery interface{}
err := json.Unmarshal([]byte(input), &mqlQuery) err := json.Unmarshal([]byte(input), &mqlQuery)
@ -104,7 +103,7 @@ func (s *Session) ExecInput(input string, c chan interface{}, _ int) {
} }
} }
func (s *Session) ToText(result interface{}) string { func (s *Session) Format(result interface{}) string {
tags := result.(map[string]graph.Value) tags := result.(map[string]graph.Value)
out := fmt.Sprintln("****") out := fmt.Sprintln("****")
tagKeys := make([]string, len(tags)) tagKeys := make([]string, len(tags))
@ -127,11 +126,11 @@ func (s *Session) ToText(result interface{}) string {
return out return out
} }
func (s *Session) BuildJSON(result interface{}) { func (s *Session) Collate(result interface{}) {
s.currentQuery.treeifyResult(result.(map[string]graph.Value)) s.currentQuery.treeifyResult(result.(map[string]graph.Value))
} }
func (s *Session) GetJSON() ([]interface{}, error) { func (s *Session) Results() (interface{}, error) {
s.currentQuery.buildResults() s.currentQuery.buildResults()
if s.currentQuery.isError() { if s.currentQuery.isError() {
return nil, s.currentQuery.err return nil, s.currentQuery.err
@ -139,7 +138,7 @@ func (s *Session) GetJSON() ([]interface{}, error) {
return s.currentQuery.results, nil return s.currentQuery.results, nil
} }
func (s *Session) ClearJSON() { func (s *Session) Clear() {
// Since we create a new Query underneath every query, clearing isn't necessary. // Since we create a new Query underneath every query, clearing isn't necessary.
return return
} }

View file

@ -26,20 +26,19 @@ const (
type Session interface { type Session interface {
// Return whether the string is a valid expression. // Return whether the string is a valid expression.
InputParses(string) (ParseResult, error) Parse(string) (ParseResult, error)
ExecInput(string, chan interface{}, int) Execute(string, chan interface{}, int)
ToText(interface{}) string Format(interface{}) string
ToggleDebug() Debug(bool)
} }
type HTTP interface { type HTTP interface {
// Return whether the string is a valid expression. // Return whether the string is a valid expression.
InputParses(string) (ParseResult, error) Parse(string) (ParseResult, error)
// Runs the query and returns individual results on the channel. // Runs the query and returns individual results on the channel.
ExecInput(string, chan interface{}, int) Execute(string, chan interface{}, int)
GetQuery(string, chan map[string]interface{}) ShapeOf(string) (interface{}, error)
BuildJSON(interface{}) Collate(interface{})
GetJSON() ([]interface{}, error) Results() (interface{}, error)
ClearJSON() Clear()
ToggleDebug()
} }

View file

@ -37,11 +37,11 @@ func NewSession(qs graph.QuadStore) *Session {
return &s return &s
} }
func (s *Session) ToggleDebug() { func (s *Session) Debug(ok bool) {
s.debug = !s.debug s.debug = ok
} }
func (s *Session) InputParses(input string) (query.ParseResult, error) { func (s *Session) Parse(input string) (query.ParseResult, error) {
var parenDepth int var parenDepth int
for i, x := range input { for i, x := range input {
if x == '(' { if x == '(' {
@ -67,7 +67,7 @@ func (s *Session) InputParses(input string) (query.ParseResult, error) {
return query.ParseFail, errors.New("invalid syntax") return query.ParseFail, errors.New("invalid syntax")
} }
func (s *Session) ExecInput(input string, out chan interface{}, limit int) { func (s *Session) Execute(input string, out chan interface{}, limit int) {
it := BuildIteratorTreeForQuery(s.qs, input) it := BuildIteratorTreeForQuery(s.qs, input)
newIt, changed := it.Optimize() newIt, changed := it.Optimize()
if changed { if changed {
@ -104,7 +104,7 @@ func (s *Session) ExecInput(input string, out chan interface{}, limit int) {
close(out) close(out)
} }
func (s *Session) ToText(result interface{}) string { func (s *Session) Format(result interface{}) string {
out := fmt.Sprintln("****") out := fmt.Sprintln("****")
tags := result.(map[string]graph.Value) tags := result.(map[string]graph.Value)
tagKeys := make([]string, len(tags)) tagKeys := make([]string, len(tags))