Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
d3e32f944a | |||
3bf9f02a9f | |||
533c767e1d | |||
84d55dbc8a | |||
5aafff6310 | |||
840aaf64ff | |||
7bbb56a328 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -23,6 +23,8 @@
|
||||
/tmp/runner-build
|
||||
/demo/tmp
|
||||
|
||||
.idea
|
||||
*.iml
|
||||
.vscode
|
||||
.DS_Store
|
||||
.swp
|
||||
|
2
Makefile
2
Makefile
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
17
core/internal/qcode/bench.9
Normal file
17
core/internal/qcode/bench.9
Normal 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
|
@ -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)
|
||||
// }
|
||||
// }
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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
112
jsn/clear.go
Normal 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
47
jsn/intstack.go
Normal 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
|
||||
}
|
||||
}
|
@ -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()
|
||||
|
||||
|
@ -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
51
jsn/sistack.go
Normal 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
|
||||
}
|
||||
}
|
51
jsn/stack.go
51
jsn/stack.go
@ -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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user