Compare commits

...

7 Commits

16 changed files with 349 additions and 64 deletions

2
.gitignore vendored
View File

@ -23,6 +23,8 @@
/tmp/runner-build
/demo/tmp
.idea
*.iml
.vscode
.DS_Store
.swp

View File

@ -22,7 +22,7 @@ BUILD_FLAGS ?= -ldflags '-s -w -X ${lastCommitSHA}=${BUILD} -X "${lastCommitTime
.PHONY: all build gen clean test run lint changlog release version help $(PLATFORMS)
test:
@go test -v ./...
@go test -v -short -race ./...
BIN_DIR := $(GOPATH)/bin
GORICE := $(BIN_DIR)/rice

View File

@ -3,6 +3,7 @@ package core
import (
"fmt"
"path"
"path/filepath"
"strings"
"github.com/spf13/viper"
@ -195,9 +196,13 @@ func newViper(configPath, configFile string) *viper.Viper {
vi.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
vi.AutomaticEnv()
vi.SetConfigName(configFile)
vi.AddConfigPath(configPath)
vi.AddConfigPath("./config")
if len(filepath.Ext(configFile)) != 0 {
vi.SetConfigFile(configFile)
} else {
vi.SetConfigName(configFile)
vi.AddConfigPath(configPath)
vi.AddConfigPath("./config")
}
return vi
}

View File

@ -9,6 +9,8 @@ import (
"os"
"sort"
"strings"
"github.com/dosco/super-graph/jsn"
)
const (
@ -230,6 +232,8 @@ func (al *List) Load() ([]Item, error) {
}
func (al *List) save(item Item) error {
var buf bytes.Buffer
item.Name = QueryName(item.Query)
item.key = strings.ToLower(item.Name)
@ -298,9 +302,16 @@ func (al *List) save(item Item) error {
}
if len(v.Vars) != 0 && !bytes.Equal(v.Vars, []byte("{}")) {
vj, err := json.MarshalIndent(v.Vars, "", " ")
buf.Reset()
if err := jsn.Clear(&buf, v.Vars); err != nil {
return fmt.Errorf("failed to clean vars: %w", err)
}
vj := json.RawMessage(buf.Bytes())
vj, err = json.MarshalIndent(vj, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal vars: %v", err)
return fmt.Errorf("failed to marshal vars: %w", err)
}
_, err = f.WriteString(fmt.Sprintf("variables %s\n\n", vj))

View File

@ -921,8 +921,6 @@ func (c *compilerContext) renderExp(ex *qcode.Exp, ti *DBTableInfo, skipNested b
st.Push('(')
case qcode.OpNot:
//fmt.Printf("1> %s %d %s %s\n", val.Op, len(val.Children), val.Children[0].Op, val.Children[1].Op)
st.Push(val.Children[0])
st.Push(qcode.OpNot)

View File

@ -260,7 +260,7 @@ type DBFunction struct {
type DBFuncParam struct {
ID int
Name string
Name sql.NullString
Type string
}
@ -291,6 +291,7 @@ ORDER BY
var funcs []DBFunction
fm := make(map[string]int)
parameterIndex := 1
for rows.Next() {
var fn, fid string
fp := DBFuncParam{}
@ -300,12 +301,18 @@ ORDER BY
return nil, err
}
if !fp.Name.Valid {
fp.Name.String = string(parameterIndex)
fp.Name.Valid = true
}
if i, ok := fm[fid]; ok {
funcs[i].Params = append(funcs[i].Params, fp)
} else {
funcs = append(funcs, DBFunction{Name: fn, Params: []DBFuncParam{fp}})
fm[fid] = len(funcs) - 1
}
parameterIndex++
}
return funcs, nil

View File

@ -0,0 +1,17 @@
goos: darwin
goarch: amd64
pkg: github.com/dosco/super-graph/core/internal/qcode
BenchmarkQCompile
BenchmarkQCompile-16 129614 8649 ns/op 3756 B/op 28 allocs/op
BenchmarkQCompileP
BenchmarkQCompileP-16 487488 2525 ns/op 3792 B/op 28 allocs/op
BenchmarkParse
BenchmarkParse-16 127582 8731 ns/op 3902 B/op 18 allocs/op
BenchmarkParseP
BenchmarkParseP-16 561373 2223 ns/op 3903 B/op 18 allocs/op
BenchmarkSchemaParse
BenchmarkSchemaParse-16 209142 5523 ns/op 3968 B/op 57 allocs/op
BenchmarkSchemaParseP
BenchmarkSchemaParseP-16 716437 1734 ns/op 3968 B/op 57 allocs/op
PASS
ok github.com/dosco/super-graph/core/internal/qcode 8.483s

View File

@ -602,7 +602,7 @@ func (t parserType) String() string {
// nodePool.Put(n)
// freeList = append(freeList, Frees{n, loc})
// } else {
// fmt.Printf(">>>>(%d) RE_FREE %d %p %s %s\n", loc, freeList[j].loc, freeList[j].n, n.Name, n.Type)
// fmt.Printf("(%d) RE_FREE %d %p %s %s\n", loc, freeList[j].loc, freeList[j].n, n.Name, n.Type)
// }
// }

View File

@ -2,6 +2,7 @@ package qcode
import (
"errors"
"github.com/chirino/graphql/schema"
"testing"
)
@ -130,7 +131,7 @@ updateThread {
}
var gql = []byte(`
products(
{products(
# returns only 30 items
limit: 30,
@ -148,7 +149,7 @@ var gql = []byte(`
id
name
price
}`)
}}`)
func BenchmarkQCompile(b *testing.B) {
qcompile, _ := NewCompiler(Config{})
@ -181,3 +182,59 @@ func BenchmarkQCompileP(b *testing.B) {
}
})
}
func BenchmarkParse(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for n := 0; n < b.N; n++ {
_, err := Parse(gql)
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkParseP(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, err := Parse(gql)
if err != nil {
b.Fatal(err)
}
}
})
}
func BenchmarkSchemaParse(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for n := 0; n < b.N; n++ {
doc := schema.QueryDocument{}
err := doc.Parse(string(gql))
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkSchemaParseP(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
doc := schema.QueryDocument{}
err := doc.Parse(string(gql))
if err != nil {
b.Fatal(err)
}
}
})
}

View File

@ -52,6 +52,7 @@ func apiV1Handler() http.Handler {
func apiV1(w http.ResponseWriter, r *http.Request) {
ct := r.Context()
w.Header().Set("Content-Type", "application/json")
//nolint: errcheck
if conf.AuthFailBlock && !auth.IsAuth(ct) {

112
jsn/clear.go Normal file
View File

@ -0,0 +1,112 @@
package jsn
import (
"bytes"
"encoding/json"
"io"
)
// Clear function wipes all scalar values from the json including those directly in an array
func Clear(w *bytes.Buffer, v []byte) error {
dec := json.NewDecoder(bytes.NewReader(v))
st := newIntStack()
isValue := false
inArray := false
n := 0
for {
var t json.Token
var err error
if t, err = dec.Token(); err == io.EOF {
break
} else if err != nil {
return err
}
switch v1 := t.(type) {
case int:
if isValue && !inArray {
w.WriteByte('0')
isValue = false
n++
}
case float64:
if isValue && !inArray {
w.WriteString(`0.0`)
isValue = false
n++
}
case bool:
if isValue && !inArray {
w.WriteString(`false`)
isValue = false
n++
}
case json.Number:
if isValue && !inArray {
w.WriteString(`0`)
isValue = false
n++
}
case nil:
if isValue && !inArray {
w.WriteString(`null`)
isValue = false
n++
}
case string:
if !isValue {
if n != 0 {
w.WriteByte(',')
}
io := int(dec.InputOffset())
w.Write(v[io-len(v1)-2 : io])
w.WriteString(`:`)
isValue = true
} else if !inArray {
w.WriteString(`""`)
isValue = false
n++
}
case json.Delim:
switch t.(json.Delim) {
case '[':
st.Push(n)
inArray = true
n = 0
case ']':
n = st.Pop()
inArray = false
isValue = false
n++
case '{':
if n != 0 && !isValue {
w.WriteByte(',')
}
st.Push(n)
inArray = false
isValue = false
n = 0
case '}':
n = st.Pop()
isValue = false
n++
}
w.WriteByte(v[dec.InputOffset()-1])
}
dec.More()
}
return nil
}

47
jsn/intstack.go Normal file
View File

@ -0,0 +1,47 @@
package jsn
type intStack struct {
stA [20]int
st []int
top int
}
// Create a new intStack
func newIntStack() *intStack {
s := &intStack{top: -1}
s.st = s.stA[:0]
return s
}
// Return the number of items in the intStack
func (s *intStack) Len() int {
return (s.top + 1)
}
// View the top item on the intStack
func (s *intStack) Peek() int {
if s.top == -1 {
return -1
}
return s.st[s.top]
}
// Pop the top item of the intStack and return it
func (s *intStack) Pop() int {
if s.top == -1 {
return -1
}
s.top--
return s.st[(s.top + 1)]
}
// Push a value onto the top of the intStack
func (s *intStack) Push(value int) {
s.top++
if len(s.st) <= s.top {
s.st = append(s.st, value)
} else {
s.st[s.top] = value
}
}

View File

@ -509,6 +509,34 @@ func TestKeys3(t *testing.T) {
}
}
func TestClear(t *testing.T) {
var buf bytes.Buffer
json := `{
"insert": {
"created_at": "now",
"test_1a": { "type1": "a", "type2": [{ "a": 2 }] },
"name": "Hello",
"updated_at": "now",
"description": "World"
},
"user": 123,
"tags": [1, 2, "what"]
}`
expected := `{"insert":{"created_at":"","test_1a":{"type1":"","type2":[{"a":0.0}]},"name":"","updated_at":"","description":""},"user":0.0,"tags":[]}`
err := Clear(&buf, []byte(json))
if err != nil {
t.Fatal(err)
}
if buf.String() != expected {
t.Log(buf.String())
t.Error("Does not match expected json")
}
}
func BenchmarkGet(b *testing.B) {
b.ReportAllocs()

View File

@ -10,7 +10,7 @@ func Keys(b []byte) [][]byte {
var k []byte
state := expectValue
st := newStack()
st := newSkipInfoStack()
ae := 0
instr := false
slash := 0

51
jsn/sistack.go Normal file
View File

@ -0,0 +1,51 @@
package jsn
type skipInfo struct {
ss, se int
}
type siStack struct {
stA [20]skipInfo
st []skipInfo
top int
}
// Create a new siStack
func newSkipInfoStack() *siStack {
s := &siStack{top: -1}
s.st = s.stA[:0]
return s
}
// Return the number of items in the siStack
func (s *siStack) Len() int {
return (s.top + 1)
}
// View the top item on the siStack
func (s *siStack) Peek() *skipInfo {
if s.top == -1 {
return nil
}
return &s.st[s.top]
}
// Pop the top item of the siStack and return it
func (s *siStack) Pop() *skipInfo {
if s.top == -1 {
return nil
}
s.top--
return &s.st[(s.top + 1)]
}
// Push a value onto the top of the siStack
func (s *siStack) Push(value skipInfo) {
s.top++
if len(s.st) <= s.top {
s.st = append(s.st, value)
} else {
s.st[s.top] = value
}
}

View File

@ -1,51 +0,0 @@
package jsn
type skipInfo struct {
ss, se int
}
type stack struct {
stA [20]skipInfo
st []skipInfo
top int
}
// Create a new stack
func newStack() *stack {
s := &stack{top: -1}
s.st = s.stA[:0]
return s
}
// Return the number of items in the stack
func (s *stack) Len() int {
return (s.top + 1)
}
// View the top item on the stack
func (s *stack) Peek() *skipInfo {
if s.top == -1 {
return nil
}
return &s.st[s.top]
}
// Pop the top item of the stack and return it
func (s *stack) Pop() *skipInfo {
if s.top == -1 {
return nil
}
s.top--
return &s.st[(s.top + 1)]
}
// Push a value onto the top of the stack
func (s *stack) Push(value skipInfo) {
s.top++
if len(s.st) <= s.top {
s.st = append(s.st, value)
} else {
s.st[s.top] = value
}
}