Add SQL RUN query statement type

This commit is contained in:
Tobie Morgan Hitchcock 2018-04-14 17:55:05 +01:00
parent ea1749f03f
commit ac19b552e5
7 changed files with 250 additions and 26 deletions

39
db/run.go Normal file
View file

@ -0,0 +1,39 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package db
import (
"context"
"github.com/abcum/surreal/sql"
)
func (e *executor) executeRun(ctx context.Context, stm *sql.RunStatement) (out []interface{}, err error) {
val, err := e.fetch(ctx, stm, nil)
if err != nil {
return nil, err
}
switch val := val.(type) {
case []interface{}:
out = val
case interface{}:
out = append(out, val)
}
return
}

106
db/run_test.go Normal file
View file

@ -0,0 +1,106 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package db
import (
"fmt"
"sync"
"testing"
"time"
"net/http"
"net/http/httptest"
. "github.com/smartystreets/goconvey/convey"
)
type Handler struct {
sync.Mutex
count int
}
func (s *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.Lock()
defer s.Unlock()
s.count++
fmt.Fprintf(w, "SERVER OK: %d", s.count)
}
func TestRun(t *testing.T) {
handler := &Handler{}
server := httptest.NewServer(handler)
defer server.Close()
Convey("Run statement which runs http requests", t, func() {
setupDB()
func() {
txt := `
USE NS test DB test;
DEFINE TABLE test PERMISSIONS FULL;
DEFINE TABLE temp PERMISSIONS FOR SELECT FULL;
DEFINE EVENT done ON test WHEN true THEN (
CREATE temp:main;
RUN http.get("` + server.URL + `");
RUN http.put("` + server.URL + `");
RUN http.post("` + server.URL + `");
RUN http.delete("` + server.URL + `");
RUN http.async.get("` + server.URL + `");
RUN http.async.put("` + server.URL + `");
RUN http.async.post("` + server.URL + `");
RUN http.async.delete("` + server.URL + `");
);
`
res, err := Execute(setupKV(), txt, nil)
So(err, ShouldBeNil)
So(res, ShouldHaveLength, 4)
So(res[1].Status, ShouldEqual, "OK")
So(res[2].Status, ShouldEqual, "OK")
}()
func() {
txt := `
USE NS test DB test;
SELECT * FROM test, temp;
CREATE test:main;
SELECT * FROM test, temp;
`
res, err := Execute(setupSC(), txt, nil)
time.Sleep(1 * time.Second)
So(err, ShouldBeNil)
So(res, ShouldHaveLength, 4)
So(res[1].Status, ShouldEqual, "OK")
So(res[1].Result, ShouldHaveLength, 0)
So(res[2].Status, ShouldEqual, "OK")
So(res[2].Result, ShouldHaveLength, 1)
So(res[3].Status, ShouldEqual, "OK")
So(res[3].Result, ShouldHaveLength, 2)
handler.Lock()
So(handler.count, ShouldEqual, 8)
handler.Unlock()
}()
})
}

View file

@ -101,6 +101,16 @@ type IfStatement struct {
Else Expr `cork:"else" codec:"else"`
}
// --------------------------------------------------
// Run
// --------------------------------------------------
// RunStatement represents a run clause.
type RunStatement struct {
RW bool `cork:"-" codec:"-"`
Expr Expr `cork:"expr" codec:"expr"`
}
// --------------------------------------------------
// LET
// --------------------------------------------------

View file

@ -930,6 +930,36 @@ func (this *IfStatement) UnmarshalCORK(r *cork.Reader) (err error) {
return
}
// --------------------------------------------------
// RunStatement
// --------------------------------------------------
func init() {
cork.Register(&RunStatement{})
}
func (this *RunStatement) Decode(src []byte) {
pack.Decode(src, this)
}
func (this *RunStatement) Encode() (dst []byte) {
return pack.Encode(this)
}
func (this *RunStatement) ExtendCORK() byte {
return 0x72
}
func (this *RunStatement) MarshalCORK(w *cork.Writer) (err error) {
w.EncodeAny(this.Expr)
return
}
func (this *RunStatement) UnmarshalCORK(r *cork.Reader) (err error) {
r.DecodeAny(&this.Expr)
return
}
// --------------------------------------------------
// LiveStatement
// --------------------------------------------------
@ -947,7 +977,7 @@ func (this *LiveStatement) Encode() (dst []byte) {
}
func (this *LiveStatement) ExtendCORK() byte {
return 0x72
return 0x73
}
func (this *LiveStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -987,7 +1017,7 @@ func (this *SelectStatement) Encode() (dst []byte) {
}
func (this *SelectStatement) ExtendCORK() byte {
return 0x73
return 0x74
}
func (this *SelectStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1041,7 +1071,7 @@ func (this *CreateStatement) Encode() (dst []byte) {
}
func (this *CreateStatement) ExtendCORK() byte {
return 0x74
return 0x75
}
func (this *CreateStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1083,7 +1113,7 @@ func (this *UpdateStatement) Encode() (dst []byte) {
}
func (this *UpdateStatement) ExtendCORK() byte {
return 0x75
return 0x76
}
func (this *UpdateStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1127,7 +1157,7 @@ func (this *DeleteStatement) Encode() (dst []byte) {
}
func (this *DeleteStatement) ExtendCORK() byte {
return 0x76
return 0x77
}
func (this *DeleteStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1171,7 +1201,7 @@ func (this *RelateStatement) Encode() (dst []byte) {
}
func (this *RelateStatement) ExtendCORK() byte {
return 0x77
return 0x78
}
func (this *RelateStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1219,7 +1249,7 @@ func (this *InsertStatement) Encode() (dst []byte) {
}
func (this *InsertStatement) ExtendCORK() byte {
return 0x78
return 0x79
}
func (this *InsertStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1261,7 +1291,7 @@ func (this *UpsertStatement) Encode() (dst []byte) {
}
func (this *UpsertStatement) ExtendCORK() byte {
return 0x79
return 0x80
}
func (this *UpsertStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1303,7 +1333,7 @@ func (this *DefineNamespaceStatement) Encode() (dst []byte) {
}
func (this *DefineNamespaceStatement) ExtendCORK() byte {
return 0x80
return 0x81
}
func (this *DefineNamespaceStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1333,7 +1363,7 @@ func (this *RemoveNamespaceStatement) Encode() (dst []byte) {
}
func (this *RemoveNamespaceStatement) ExtendCORK() byte {
return 0x81
return 0x82
}
func (this *RemoveNamespaceStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1363,7 +1393,7 @@ func (this *DefineDatabaseStatement) Encode() (dst []byte) {
}
func (this *DefineDatabaseStatement) ExtendCORK() byte {
return 0x82
return 0x83
}
func (this *DefineDatabaseStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1393,7 +1423,7 @@ func (this *RemoveDatabaseStatement) Encode() (dst []byte) {
}
func (this *RemoveDatabaseStatement) ExtendCORK() byte {
return 0x83
return 0x84
}
func (this *RemoveDatabaseStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1423,7 +1453,7 @@ func (this *DefineLoginStatement) Encode() (dst []byte) {
}
func (this *DefineLoginStatement) ExtendCORK() byte {
return 0x84
return 0x85
}
func (this *DefineLoginStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1459,7 +1489,7 @@ func (this *RemoveLoginStatement) Encode() (dst []byte) {
}
func (this *RemoveLoginStatement) ExtendCORK() byte {
return 0x85
return 0x86
}
func (this *RemoveLoginStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1491,7 +1521,7 @@ func (this *DefineTokenStatement) Encode() (dst []byte) {
}
func (this *DefineTokenStatement) ExtendCORK() byte {
return 0x86
return 0x87
}
func (this *DefineTokenStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1527,7 +1557,7 @@ func (this *RemoveTokenStatement) Encode() (dst []byte) {
}
func (this *RemoveTokenStatement) ExtendCORK() byte {
return 0x87
return 0x88
}
func (this *RemoveTokenStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1559,7 +1589,7 @@ func (this *DefineScopeStatement) Encode() (dst []byte) {
}
func (this *DefineScopeStatement) ExtendCORK() byte {
return 0x88
return 0x89
}
func (this *DefineScopeStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1603,7 +1633,7 @@ func (this *RemoveScopeStatement) Encode() (dst []byte) {
}
func (this *RemoveScopeStatement) ExtendCORK() byte {
return 0x89
return 0x90
}
func (this *RemoveScopeStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1633,7 +1663,7 @@ func (this *DefineTableStatement) Encode() (dst []byte) {
}
func (this *DefineTableStatement) ExtendCORK() byte {
return 0x90
return 0x91
}
func (this *DefineTableStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1679,7 +1709,7 @@ func (this *RemoveTableStatement) Encode() (dst []byte) {
}
func (this *RemoveTableStatement) ExtendCORK() byte {
return 0x91
return 0x92
}
func (this *RemoveTableStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1709,7 +1739,7 @@ func (this *DefineEventStatement) Encode() (dst []byte) {
}
func (this *DefineEventStatement) ExtendCORK() byte {
return 0x92
return 0x93
}
func (this *DefineEventStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1745,7 +1775,7 @@ func (this *RemoveEventStatement) Encode() (dst []byte) {
}
func (this *RemoveEventStatement) ExtendCORK() byte {
return 0x93
return 0x94
}
func (this *RemoveEventStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1777,7 +1807,7 @@ func (this *DefineFieldStatement) Encode() (dst []byte) {
}
func (this *DefineFieldStatement) ExtendCORK() byte {
return 0x94
return 0x95
}
func (this *DefineFieldStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1821,7 +1851,7 @@ func (this *RemoveFieldStatement) Encode() (dst []byte) {
}
func (this *RemoveFieldStatement) ExtendCORK() byte {
return 0x95
return 0x96
}
func (this *RemoveFieldStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1853,7 +1883,7 @@ func (this *DefineIndexStatement) Encode() (dst []byte) {
}
func (this *DefineIndexStatement) ExtendCORK() byte {
return 0x96
return 0x97
}
func (this *DefineIndexStatement) MarshalCORK(w *cork.Writer) (err error) {
@ -1889,7 +1919,7 @@ func (this *RemoveIndexStatement) Encode() (dst []byte) {
}
func (this *RemoveIndexStatement) ExtendCORK() byte {
return 0x97
return 0x98
}
func (this *RemoveIndexStatement) MarshalCORK(w *cork.Writer) (err error) {

31
sql/run.go Normal file
View file

@ -0,0 +1,31 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sql
func (p *parser) parseRunStatement() (stmt *RunStatement, err error) {
stmt = &RunStatement{}
stmt.Expr, err = p.parseExpr()
// If this query has any subqueries which
// need to alter the database then mark
// this query as a writeable statement.
stmt.RW = p.buf.rw
return
}

View file

@ -168,6 +168,12 @@ func (this InfoStatement) String() string {
}
}
func (this RunStatement) String() string {
return print("RUN %v",
this.Expr,
)
}
func (this IfStatement) String() string {
m := make([]string, len(this.Cond))
for k := range this.Cond {

View file

@ -169,6 +169,7 @@ const (
RELATE
REMOVE
RETURN
RUN
SCHEMAFULL
SCHEMALESS
SCOPE
@ -339,6 +340,7 @@ var tokens = [...]string{
RELATE: "RELATE",
REMOVE: "REMOVE",
RETURN: "RETURN",
RUN: "RUN",
SCHEMAFULL: "SCHEMAFULL",
SCHEMALESS: "SCHEMALESS",
SCOPE: "SCOPE",