fix: update allow list parser to support fragments
This commit is contained in:
parent
33f3fefbf3
commit
b26cdbf960
|
@ -197,30 +197,26 @@ func (c *Config) AddRoleTable(role string, table string, conf interface{}) error
|
||||||
// ReadInConfig function reads in the config file for the environment specified in the GO_ENV
|
// ReadInConfig function reads in the config file for the environment specified in the GO_ENV
|
||||||
// environment variable. This is the best way to create a new Super Graph config.
|
// environment variable. This is the best way to create a new Super Graph config.
|
||||||
func ReadInConfig(configFile string) (*Config, error) {
|
func ReadInConfig(configFile string) (*Config, error) {
|
||||||
cpath := path.Dir(configFile)
|
cp := path.Dir(configFile)
|
||||||
cfile := path.Base(configFile)
|
vi := newViper(cp, path.Base(configFile))
|
||||||
vi := newViper(cpath, cfile)
|
|
||||||
|
|
||||||
if err := vi.ReadInConfig(); err != nil {
|
if err := vi.ReadInConfig(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
inherits := vi.GetString("inherits")
|
if pcf := vi.GetString("inherits"); pcf != "" {
|
||||||
|
cf := vi.ConfigFileUsed()
|
||||||
if inherits != "" {
|
vi = newViper(cp, pcf)
|
||||||
vi = newViper(cpath, inherits)
|
|
||||||
|
|
||||||
if err := vi.ReadInConfig(); err != nil {
|
if err := vi.ReadInConfig(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if vi.IsSet("inherits") {
|
if v := vi.GetString("inherits"); v != "" {
|
||||||
return nil, fmt.Errorf("inherited config (%s) cannot itself inherit (%s)",
|
return nil, fmt.Errorf("inherited config (%s) cannot itself inherit (%s)", pcf, v)
|
||||||
inherits,
|
|
||||||
vi.GetString("inherits"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vi.SetConfigName(cfile)
|
vi.SetConfigFile(cf)
|
||||||
|
|
||||||
if err := vi.MergeInConfig(); err != nil {
|
if err := vi.MergeInConfig(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -234,7 +230,7 @@ func ReadInConfig(configFile string) (*Config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.AllowListFile == "" {
|
if c.AllowListFile == "" {
|
||||||
c.AllowListFile = path.Join(cpath, "allow.list")
|
c.AllowListFile = path.Join(cp, "allow.list")
|
||||||
}
|
}
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
|
@ -248,7 +244,7 @@ func newViper(configPath, configFile string) *viper.Viper {
|
||||||
vi.AutomaticEnv()
|
vi.AutomaticEnv()
|
||||||
|
|
||||||
if filepath.Ext(configFile) != "" {
|
if filepath.Ext(configFile) != "" {
|
||||||
vi.SetConfigFile(configFile)
|
vi.SetConfigFile(path.Join(configPath, configFile))
|
||||||
} else {
|
} else {
|
||||||
vi.SetConfigName(configFile)
|
vi.SetConfigName(configFile)
|
||||||
vi.AddConfigPath(configPath)
|
vi.AddConfigPath(configPath)
|
||||||
|
|
|
@ -10,21 +10,23 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/scanner"
|
||||||
|
|
||||||
"github.com/chirino/graphql/schema"
|
"github.com/chirino/graphql/schema"
|
||||||
"github.com/dosco/super-graph/jsn"
|
"github.com/dosco/super-graph/jsn"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AL_QUERY int = iota + 1
|
expComment = iota + 1
|
||||||
AL_VARS
|
expVar
|
||||||
|
expQuery
|
||||||
)
|
)
|
||||||
|
|
||||||
type Item struct {
|
type Item struct {
|
||||||
Name string
|
Name string
|
||||||
key string
|
key string
|
||||||
Query string
|
Query string
|
||||||
Vars json.RawMessage
|
Vars string
|
||||||
Comment string
|
Comment string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,121 +128,101 @@ func (al *List) Set(vars []byte, query, comment string) error {
|
||||||
return errors.New("empty query")
|
return errors.New("empty query")
|
||||||
}
|
}
|
||||||
|
|
||||||
var q string
|
|
||||||
|
|
||||||
for i := 0; i < len(query); i++ {
|
|
||||||
c := query[i]
|
|
||||||
if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' {
|
|
||||||
q = query
|
|
||||||
break
|
|
||||||
|
|
||||||
} else if c == '{' {
|
|
||||||
q = "query " + query
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
al.saveChan <- Item{
|
al.saveChan <- Item{
|
||||||
Comment: comment,
|
Comment: comment,
|
||||||
Query: q,
|
Query: query,
|
||||||
Vars: vars,
|
Vars: string(vars),
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (al *List) Load() ([]Item, error) {
|
func (al *List) Load() ([]Item, error) {
|
||||||
var list []Item
|
|
||||||
varString := "variables"
|
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(al.filepath)
|
b, err := ioutil.ReadFile(al.filepath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return list, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(b) == 0 {
|
return parse(string(b), al.filepath)
|
||||||
return list, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var comment bytes.Buffer
|
func parse(b string, filename string) ([]Item, error) {
|
||||||
var varBytes []byte
|
var items []Item
|
||||||
|
|
||||||
itemMap := make(map[string]struct{})
|
var s scanner.Scanner
|
||||||
|
s.Init(strings.NewReader(b))
|
||||||
|
s.Filename = filename
|
||||||
|
s.Mode ^= scanner.SkipComments
|
||||||
|
|
||||||
s, e, c := 0, 0, 0
|
var op, sp scanner.Position
|
||||||
ty := 0
|
var item Item
|
||||||
|
|
||||||
for {
|
newComment := false
|
||||||
fq := false
|
st := expComment
|
||||||
|
|
||||||
if c == 0 && b[e] == '#' {
|
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
|
||||||
s = e
|
txt := s.TokenText()
|
||||||
for e < len(b) && b[e] != '\n' {
|
|
||||||
e++
|
|
||||||
}
|
|
||||||
if (e - s) > 2 {
|
|
||||||
comment.Write(b[(s + 1):(e + 1)])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if e >= len(b) {
|
switch {
|
||||||
break
|
case strings.HasPrefix(txt, "/*"):
|
||||||
|
if st == expQuery {
|
||||||
|
v := b[sp.Offset:s.Pos().Offset]
|
||||||
|
item.Query = strings.TrimSpace(v[:strings.LastIndexByte(v, '}')+1])
|
||||||
|
items = append(items, item)
|
||||||
}
|
}
|
||||||
|
item = Item{Comment: strings.TrimSpace(txt[2 : len(txt)-2])}
|
||||||
|
sp = s.Pos()
|
||||||
|
st = expComment
|
||||||
|
newComment = true
|
||||||
|
|
||||||
if matchPrefix(b, e, "query") || matchPrefix(b, e, "mutation") {
|
case !newComment && strings.HasPrefix(txt, "#"):
|
||||||
if c == 0 {
|
if st == expQuery {
|
||||||
s = e
|
v := b[sp.Offset:s.Pos().Offset]
|
||||||
|
item.Query = strings.TrimSpace(v[:strings.LastIndexByte(v, '}')+1])
|
||||||
|
items = append(items, item)
|
||||||
}
|
}
|
||||||
ty = AL_QUERY
|
item = Item{}
|
||||||
} else if matchPrefix(b, e, varString) {
|
sp = s.Pos()
|
||||||
if c == 0 {
|
st = expComment
|
||||||
s = e + len(varString) + 1
|
|
||||||
}
|
|
||||||
ty = AL_VARS
|
|
||||||
} else if b[e] == '{' {
|
|
||||||
c++
|
|
||||||
|
|
||||||
} else if b[e] == '}' {
|
case strings.HasPrefix(txt, "variables"):
|
||||||
c--
|
if st == expComment {
|
||||||
|
v := b[sp.Offset:s.Pos().Offset]
|
||||||
|
item.Comment = strings.TrimSpace(v[:strings.IndexByte(v, '\n')])
|
||||||
|
}
|
||||||
|
sp = s.Pos()
|
||||||
|
st = expVar
|
||||||
|
|
||||||
if c == 0 {
|
case isGraphQL(txt):
|
||||||
if ty == AL_QUERY {
|
if st == expVar {
|
||||||
fq = true
|
v := b[sp.Offset:s.Pos().Offset]
|
||||||
} else if ty == AL_VARS {
|
item.Vars = strings.TrimSpace(v[:strings.LastIndexByte(v, '}')+1])
|
||||||
varBytes = b[s:(e + 1)]
|
|
||||||
}
|
}
|
||||||
ty = 0
|
sp = op
|
||||||
}
|
st = expQuery
|
||||||
}
|
|
||||||
|
|
||||||
if fq {
|
|
||||||
query := string(b[s:(e + 1)])
|
|
||||||
name := QueryName(query)
|
|
||||||
key := strings.ToLower(name)
|
|
||||||
|
|
||||||
if _, ok := itemMap[key]; !ok {
|
|
||||||
v := Item{
|
|
||||||
Name: name,
|
|
||||||
key: key,
|
|
||||||
Query: query,
|
|
||||||
Vars: varBytes,
|
|
||||||
Comment: comment.String(),
|
|
||||||
}
|
|
||||||
list = append(list, v)
|
|
||||||
comment.Reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
varBytes = nil
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
op = s.Pos()
|
||||||
e++
|
|
||||||
if e >= len(b) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return list, nil
|
if st == expQuery {
|
||||||
|
v := b[sp.Offset:s.Pos().Offset]
|
||||||
|
item.Query = strings.TrimSpace(v[:strings.LastIndexByte(v, '}')+1])
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range items {
|
||||||
|
items[i].Name = QueryName(items[i].Query)
|
||||||
|
items[i].key = strings.ToLower(items[i].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isGraphQL(s string) bool {
|
||||||
|
return strings.HasPrefix(s, "query") ||
|
||||||
|
strings.HasPrefix(s, "mutation") ||
|
||||||
|
strings.HasPrefix(s, "subscription")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (al *List) save(item Item) error {
|
func (al *List) save(item Item) error {
|
||||||
|
@ -297,57 +279,39 @@ func (al *List) save(item Item) error {
|
||||||
return strings.Compare(list[i].key, list[j].key) == -1
|
return strings.Compare(list[i].key, list[j].key) == -1
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, v := range list {
|
for i, v := range list {
|
||||||
cmtLines := strings.Split(v.Comment, "\n")
|
var vars string
|
||||||
|
if v.Vars != "" {
|
||||||
i := 0
|
|
||||||
for _, c := range cmtLines {
|
|
||||||
if c = strings.TrimSpace(c); c == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := f.WriteString(fmt.Sprintf("# %s\n", c))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
if i != 0 {
|
|
||||||
if _, err := f.WriteString("\n"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if _, err := f.WriteString(fmt.Sprintf("# Query named %s\n\n", v.Name)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(v.Vars) != 0 && !bytes.Equal(v.Vars, []byte("{}")) {
|
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
|
if err := jsn.Clear(&buf, []byte(v.Vars)); err != nil {
|
||||||
if err := jsn.Clear(&buf, v.Vars); err != nil {
|
continue
|
||||||
return fmt.Errorf("failed to clean vars: %w", err)
|
|
||||||
}
|
}
|
||||||
vj := json.RawMessage(buf.Bytes())
|
vj := json.RawMessage(buf.Bytes())
|
||||||
|
|
||||||
vj, err = json.MarshalIndent(vj, "", " ")
|
if vj, err = json.MarshalIndent(vj, "", " "); err != nil {
|
||||||
if err != nil {
|
continue
|
||||||
return fmt.Errorf("failed to marshal vars: %w", err)
|
}
|
||||||
|
vars = string(vj)
|
||||||
|
}
|
||||||
|
list[i].Vars = vars
|
||||||
|
list[i].Comment = strings.TrimSpace(v.Comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = f.WriteString(fmt.Sprintf("variables %s\n\n", vj))
|
for _, v := range list {
|
||||||
|
if v.Comment != "" {
|
||||||
|
f.WriteString(fmt.Sprintf("/* %s */\n\n", v.Comment))
|
||||||
|
} else {
|
||||||
|
f.WriteString(fmt.Sprintf("/* %s */\n\n", v.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Vars != "" {
|
||||||
|
_, err = f.WriteString(fmt.Sprintf("variables %s\n\n", v.Vars))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Query[0] == '{' {
|
|
||||||
_, err = f.WriteString(fmt.Sprintf("query %s\n\n", v.Query))
|
|
||||||
} else {
|
|
||||||
_, err = f.WriteString(fmt.Sprintf("%s\n\n", v.Query))
|
_, err = f.WriteString(fmt.Sprintf("%s\n\n", v.Query))
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,3 +82,160 @@ func TestGQLName5(t *testing.T) {
|
||||||
t.Fatal("Name should be empty, not ", name)
|
t.Fatal("Name should be empty, not ", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParse1(t *testing.T) {
|
||||||
|
var al = `
|
||||||
|
# Hello world
|
||||||
|
|
||||||
|
variables {
|
||||||
|
"data": {
|
||||||
|
"slug": "",
|
||||||
|
"body": "",
|
||||||
|
"post": {
|
||||||
|
"connect": {
|
||||||
|
"slug": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation createComment {
|
||||||
|
comment(insert: $data) {
|
||||||
|
slug
|
||||||
|
body
|
||||||
|
createdAt: created_at
|
||||||
|
totalVotes: cached_votes_total
|
||||||
|
totalReplies: cached_replies_total
|
||||||
|
vote: comment_vote(where: {user_id: {eq: $user_id}}) {
|
||||||
|
created_at
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
author: user {
|
||||||
|
slug
|
||||||
|
firstName: first_name
|
||||||
|
lastName: last_name
|
||||||
|
pictureURL: picture_url
|
||||||
|
bio
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Query named createPost
|
||||||
|
|
||||||
|
query createPost {
|
||||||
|
post(insert: $data) {
|
||||||
|
slug
|
||||||
|
body
|
||||||
|
published
|
||||||
|
createdAt: created_at
|
||||||
|
totalVotes: cached_votes_total
|
||||||
|
totalComments: cached_comments_total
|
||||||
|
vote: post_vote(where: {user_id: {eq: $user_id}}) {
|
||||||
|
created_at
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
author: user {
|
||||||
|
slug
|
||||||
|
firstName: first_name
|
||||||
|
lastName: last_name
|
||||||
|
pictureURL: picture_url
|
||||||
|
bio
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
_, err := parse(al, "allow.list")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParse2(t *testing.T) {
|
||||||
|
var al = `
|
||||||
|
/* Hello world */
|
||||||
|
|
||||||
|
variables {
|
||||||
|
"data": {
|
||||||
|
"slug": "",
|
||||||
|
"body": "",
|
||||||
|
"post": {
|
||||||
|
"connect": {
|
||||||
|
"slug": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation createComment {
|
||||||
|
comment(insert: $data) {
|
||||||
|
slug
|
||||||
|
body
|
||||||
|
createdAt: created_at
|
||||||
|
totalVotes: cached_votes_total
|
||||||
|
totalReplies: cached_replies_total
|
||||||
|
vote: comment_vote(where: {user_id: {eq: $user_id}}) {
|
||||||
|
created_at
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
author: user {
|
||||||
|
slug
|
||||||
|
firstName: first_name
|
||||||
|
lastName: last_name
|
||||||
|
pictureURL: picture_url
|
||||||
|
bio
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Query named createPost
|
||||||
|
*/
|
||||||
|
|
||||||
|
variables {
|
||||||
|
"data": {
|
||||||
|
"thread": {
|
||||||
|
"connect": {
|
||||||
|
"slug": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"slug": "",
|
||||||
|
"published": false,
|
||||||
|
"body": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query createPost {
|
||||||
|
post(insert: $data) {
|
||||||
|
slug
|
||||||
|
body
|
||||||
|
published
|
||||||
|
createdAt: created_at
|
||||||
|
totalVotes: cached_votes_total
|
||||||
|
totalComments: cached_comments_total
|
||||||
|
vote: post_vote(where: {user_id: {eq: $user_id}}) {
|
||||||
|
created_at
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
author: user {
|
||||||
|
slug
|
||||||
|
firstName: first_name
|
||||||
|
lastName: last_name
|
||||||
|
pictureURL: picture_url
|
||||||
|
bio
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
_, err := parse(al, "allow.list")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package qcode
|
package qcode
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash/maphash"
|
"hash/maphash"
|
||||||
|
@ -329,6 +330,8 @@ func (p *Parser) parseFields(fields []Field) ([]Field, error) {
|
||||||
return nil, fmt.Errorf("unexpected token: %s", p.peekNext())
|
return nil, fmt.Errorf("unexpected token: %s", p.peekNext())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fm := make(map[uint64]struct{})
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if p.peek(itemEOF) {
|
if p.peek(itemEOF) {
|
||||||
p.ignore()
|
p.ignore()
|
||||||
|
@ -385,6 +388,20 @@ func (p *Parser) parseFields(fields []Field) ([]Field, error) {
|
||||||
f := &fields[i]
|
f := &fields[i]
|
||||||
f.ID = int32(i)
|
f.ID = int32(i)
|
||||||
|
|
||||||
|
// var name string
|
||||||
|
|
||||||
|
// if f.Alias != "" {
|
||||||
|
// name = f.Alias
|
||||||
|
// } else {
|
||||||
|
// name = f.Name
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if _, ok := fm[name]; ok {
|
||||||
|
// continue
|
||||||
|
// } else {
|
||||||
|
// fm[name] = struct{}{}
|
||||||
|
// }
|
||||||
|
|
||||||
// If this is the top-level point the parent to the parent of the
|
// If this is the top-level point the parent to the parent of the
|
||||||
// previous field.
|
// previous field.
|
||||||
if f.ParentID == -1 {
|
if f.ParentID == -1 {
|
||||||
|
@ -416,6 +433,20 @@ func (p *Parser) parseFields(fields []Field) ([]Field, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// var name string
|
||||||
|
|
||||||
|
// if f.Alias != "" {
|
||||||
|
// name = f.Alias
|
||||||
|
// } else {
|
||||||
|
// name = f.Name
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if _, ok := fm[name]; ok {
|
||||||
|
// continue
|
||||||
|
// } else {
|
||||||
|
// fm[name] = struct{}{}
|
||||||
|
// }
|
||||||
|
|
||||||
if st.Len() == 0 {
|
if st.Len() == 0 {
|
||||||
f.ParentID = -1
|
f.ParentID = -1
|
||||||
} else {
|
} else {
|
||||||
|
@ -685,6 +716,16 @@ func (p *Parser) reset(to int) {
|
||||||
p.pos = to
|
p.pos = to
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Parser) fHash(name string, parentID int32) uint64 {
|
||||||
|
var b []byte
|
||||||
|
binary.LittleEndian.PutUint32(b, uint32(parentID))
|
||||||
|
p.h.WriteString(name)
|
||||||
|
p.h.Write(b)
|
||||||
|
v := p.h.Sum64()
|
||||||
|
p.h.Reset()
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
func b2s(b []byte) string {
|
func b2s(b []byte) string {
|
||||||
return *(*string)(unsafe.Pointer(&b))
|
return *(*string)(unsafe.Pointer(&b))
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,6 +239,29 @@ var gql = []byte(`
|
||||||
price
|
price
|
||||||
}}`)
|
}}`)
|
||||||
|
|
||||||
|
var gqlWithFragments = []byte(`
|
||||||
|
fragment userFields1 on user {
|
||||||
|
id
|
||||||
|
email
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
|
||||||
|
query {
|
||||||
|
users {
|
||||||
|
...userFields2
|
||||||
|
|
||||||
|
created_at
|
||||||
|
...userFields1
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment userFields2 on user {
|
||||||
|
first_name
|
||||||
|
last_name
|
||||||
|
__typename
|
||||||
|
}`)
|
||||||
|
|
||||||
func BenchmarkQCompile(b *testing.B) {
|
func BenchmarkQCompile(b *testing.B) {
|
||||||
qcompile, _ := NewCompiler(Config{})
|
qcompile, _ := NewCompiler(Config{})
|
||||||
|
|
||||||
|
@ -271,6 +294,21 @@ func BenchmarkQCompileP(b *testing.B) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkQCompileFragment(b *testing.B) {
|
||||||
|
qcompile, _ := NewCompiler(Config{})
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
b.ReportAllocs()
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
_, err := qcompile.Compile(gqlWithFragments, "user")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkParse(b *testing.B) {
|
func BenchmarkParse(b *testing.B) {
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
@ -298,6 +336,18 @@ func BenchmarkParseP(b *testing.B) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkParseFragment(b *testing.B) {
|
||||||
|
b.ResetTimer()
|
||||||
|
b.ReportAllocs()
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
_, err := Parse(gqlWithFragments)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkSchemaParse(b *testing.B) {
|
func BenchmarkSchemaParse(b *testing.B) {
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
|
@ -419,6 +419,7 @@ func (com *Compiler) compileQuery(qc *QCode, op *Operation, role string) error {
|
||||||
com.AddFilters(qc, s, role)
|
com.AddFilters(qc, s, role)
|
||||||
|
|
||||||
s.Cols = make([]Column, 0, len(field.Children))
|
s.Cols = make([]Column, 0, len(field.Children))
|
||||||
|
cm := make(map[string]struct{})
|
||||||
action = QTQuery
|
action = QTQuery
|
||||||
|
|
||||||
for _, cid := range field.Children {
|
for _, cid := range field.Children {
|
||||||
|
@ -428,19 +429,28 @@ func (com *Compiler) compileQuery(qc *QCode, op *Operation, role string) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fname string
|
||||||
|
|
||||||
|
if f.Alias != "" {
|
||||||
|
fname = f.Alias
|
||||||
|
} else {
|
||||||
|
fname = f.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := cm[fname]; ok {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
cm[fname] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
if len(f.Children) != 0 {
|
if len(f.Children) != 0 {
|
||||||
val := f.ID | (s.ID << 16)
|
val := f.ID | (s.ID << 16)
|
||||||
st.Push(val)
|
st.Push(val)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
col := Column{Name: f.Name}
|
col := Column{Name: f.Name, FieldName: fname}
|
||||||
|
|
||||||
if len(f.Alias) != 0 {
|
|
||||||
col.FieldName = f.Alias
|
|
||||||
} else {
|
|
||||||
col.FieldName = f.Name
|
|
||||||
}
|
|
||||||
s.Cols = append(s.Cols, col)
|
s.Cols = append(s.Cols, col)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,17 +28,18 @@ func (sg *SuperGraph) prepare(q *query, role string) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
qb := []byte(q.ai.Query)
|
qb := []byte(q.ai.Query)
|
||||||
|
vars := []byte(q.ai.Vars)
|
||||||
|
|
||||||
switch q.qt {
|
switch q.qt {
|
||||||
case qcode.QTQuery:
|
case qcode.QTQuery:
|
||||||
if sg.abacEnabled {
|
if sg.abacEnabled {
|
||||||
stmts, err = sg.buildMultiStmt(qb, q.ai.Vars)
|
stmts, err = sg.buildMultiStmt(qb, vars)
|
||||||
} else {
|
} else {
|
||||||
stmts, err = sg.buildRoleStmt(qb, q.ai.Vars, role)
|
stmts, err = sg.buildRoleStmt(qb, vars, role)
|
||||||
}
|
}
|
||||||
|
|
||||||
case qcode.QTMutation:
|
case qcode.QTMutation:
|
||||||
stmts, err = sg.buildRoleStmt(qb, q.ai.Vars, role)
|
stmts, err = sg.buildRoleStmt(qb, vars, role)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -66,7 +66,7 @@ func newViper(configPath, configFile string) *viper.Viper {
|
||||||
vi.SetDefault("host_port", "0.0.0.0:8080")
|
vi.SetDefault("host_port", "0.0.0.0:8080")
|
||||||
vi.SetDefault("web_ui", false)
|
vi.SetDefault("web_ui", false)
|
||||||
vi.SetDefault("enable_tracing", false)
|
vi.SetDefault("enable_tracing", false)
|
||||||
vi.SetDefault("auth_fail_block", "always")
|
vi.SetDefault("auth_fail_block", false)
|
||||||
vi.SetDefault("seed_file", "seed.js")
|
vi.SetDefault("seed_file", "seed.js")
|
||||||
|
|
||||||
vi.SetDefault("default_block", true)
|
vi.SetDefault("default_block", true)
|
||||||
|
|
Loading…
Reference in New Issue