Reduce realloc of maps and slices

This commit is contained in:
Vikram Rangnekar 2019-04-07 01:12:11 -04:00
parent b562e1603e
commit 8acc3ed08d
6 changed files with 65 additions and 64 deletions

View File

@ -19,13 +19,14 @@ I wanted a GraphQL server that just worked the second you deployed it without ha
And so after a lot of coffee and some avocado toasts Super Graph was born. An instant GraphQL API service that's high performance and easy to deploy. I hope you find it as useful as I do and there's a lot more coming so hit that :star: to stay in the loop. And so after a lot of coffee and some avocado toasts Super Graph was born. An instant GraphQL API service that's high performance and easy to deploy. I hope you find it as useful as I do and there's a lot more coming so hit that :star: to stay in the loop.
## Features ## Features
- Support for Rails database conventions - Works with Rails database schemas
- Automatically learns schemas and relationships
- Belongs-To, One-To-Many and Many-To-Many table relationships - Belongs-To, One-To-Many and Many-To-Many table relationships
- Devise, Warden encrypted and signed session cookies - Full text search and Aggregations
- Redis, Memcache and Cookie session stores - Rails Auth supported (Redis, Memcache, Cookie)
- JWT tokens supported from providers like Auth0 - JWT tokens supported (Auth0, etc)
- Generates highly optimized and fast Postgres SQL queries - Highly optimized and fast Postgres SQL queries
- Customize through a simple config file - Configure with a simple config file
- High performance GO codebase - High performance GO codebase
- Tiny docker image and low memory requirements - Tiny docker image and low memory requirements

View File

@ -274,7 +274,7 @@ func (v *selectBlock) renderBaseSelect(w io.Writer, schema *DBSchema, childCols
isFil := v.sel.Where != nil isFil := v.sel.Where != nil
isAgg := false isAgg := false
searchVal := findArgVal(v.sel, "search") _, isSearch := v.sel.Args["search"]
io.WriteString(w, " FROM (SELECT ") io.WriteString(w, " FROM (SELECT ")
@ -284,15 +284,19 @@ func (v *selectBlock) renderBaseSelect(w io.Writer, schema *DBSchema, childCols
if !isRealCol { if !isRealCol {
switch { switch {
case searchVal != nil && cn == "search_rank": case isSearch && cn == "search_rank":
cn = v.ti.TSVCol cn = v.ti.TSVCol
fmt.Fprintf(w, `ts_rank("%s"."%s", to_tsquery('%s')) AS %s`, arg := v.sel.Args["search"]
v.sel.Table, cn, searchVal.Val, col.Name)
case searchVal != nil && strings.HasPrefix(cn, "search_headline_"): fmt.Fprintf(w, `ts_rank("%s"."%s", to_tsquery('%s')) AS %s`,
v.sel.Table, cn, arg.Val, col.Name)
case isSearch && strings.HasPrefix(cn, "search_headline_"):
cn = cn[16:] cn = cn[16:]
arg := v.sel.Args["search"]
fmt.Fprintf(w, `ts_headline("%s"."%s", to_tsquery('%s')) AS %s`, fmt.Fprintf(w, `ts_headline("%s"."%s", to_tsquery('%s')) AS %s`,
v.sel.Table, cn, searchVal.Val, col.Name) v.sel.Table, cn, arg.Val, col.Name)
default: default:
pl := funcPrefixLen(cn) pl := funcPrefixLen(cn)
@ -647,12 +651,3 @@ func funcPrefixLen(fn string) int {
} }
return 0 return 0
} }
func findArgVal(sel *qcode.Select, name string) *qcode.Node {
for i := range sel.Args {
if sel.Args[i].Name == name {
return sel.Args[i].Val
}
}
return nil
}

View File

@ -4,7 +4,7 @@ import "regexp"
func NewVariables(varlist map[string]string) map[string]string { func NewVariables(varlist map[string]string) map[string]string {
re := regexp.MustCompile(`(?mi)\$([a-zA-Z0-9_.]+)`) re := regexp.MustCompile(`(?mi)\$([a-zA-Z0-9_.]+)`)
vars := make(map[string]string) vars := make(map[string]string, len(varlist))
for k, v := range varlist { for k, v := range varlist {
vars[k] = re.ReplaceAllString(v, `{{$1}}`) vars[k] = re.ReplaceAllString(v, `{{$1}}`)

View File

@ -59,13 +59,15 @@ func (t parserType) String() string {
} }
type Operation struct { type Operation struct {
Type parserType Type parserType
Name string Name string
Args []*Arg Args []*Arg
Fields []*Field Fields []*Field
FieldLen int16
} }
type Field struct { type Field struct {
ID int16
Name string Name string
Alias string Alias string
Args []*Arg Args []*Arg
@ -200,10 +202,12 @@ func (p *Parser) parseOpByType(ty parserType) (*Operation, error) {
if p.peek(itemObjOpen) { if p.peek(itemObjOpen) {
p.ignore() p.ignore()
op.Fields, err = p.parseFields() n := int16(0)
op.Fields, n, err = p.parseFields()
if err != nil { if err != nil {
return nil, err return nil, err
} }
op.FieldLen = n
} }
if p.peek(itemObjClose) { if p.peek(itemObjClose) {
@ -233,9 +237,10 @@ func (p *Parser) parseOp() (*Operation, error) {
return nil, errors.New("unknown operation type") return nil, errors.New("unknown operation type")
} }
func (p *Parser) parseFields() ([]*Field, error) { func (p *Parser) parseFields() ([]*Field, int16, error) {
var roots []*Field var roots []*Field
st := util.NewStack() st := util.NewStack()
i := int16(0)
for { for {
if p.peek(itemObjClose) { if p.peek(itemObjClose) {
@ -248,14 +253,20 @@ func (p *Parser) parseFields() ([]*Field, error) {
continue continue
} }
if i > 500 {
return nil, 0, errors.New("too many fields")
}
if p.peek(itemName) == false { if p.peek(itemName) == false {
return nil, errors.New("expecting an alias or field name") return nil, 0, errors.New("expecting an alias or field name")
} }
field, err := p.parseField() field, err := p.parseField()
if err != nil { if err != nil {
return nil, err return nil, 0, err
} }
field.ID = i
i++
if st.Len() == 0 { if st.Len() == 0 {
roots = append(roots, field) roots = append(roots, field)
@ -264,7 +275,7 @@ func (p *Parser) parseFields() ([]*Field, error) {
intf := st.Peek() intf := st.Peek()
parent, ok := intf.(*Field) parent, ok := intf.(*Field)
if !ok || parent == nil { if !ok || parent == nil {
return nil, fmt.Errorf("unexpected value encountered %v", intf) return nil, 0, fmt.Errorf("unexpected value encountered %v", intf)
} }
field.Parent = parent field.Parent = parent
parent.Children = append(parent.Children, field) parent.Children = append(parent.Children, field)
@ -276,7 +287,7 @@ func (p *Parser) parseFields() ([]*Field, error) {
} }
} }
return roots, nil return roots, i, nil
} }
func (p *Parser) parseField() (*Field, error) { func (p *Parser) parseField() (*Field, error) {

View File

@ -2,7 +2,6 @@ package qcode
import ( import (
"fmt" "fmt"
"regexp"
"strings" "strings"
"github.com/dosco/super-graph/util" "github.com/dosco/super-graph/util"
@ -25,7 +24,7 @@ type Column struct {
type Select struct { type Select struct {
ID int16 ID int16
Args []*Arg Args map[string]*Node
AsList bool AsList bool
Table string Table string
Singular string Singular string
@ -181,7 +180,7 @@ const (
) )
type FilterMap map[string]*Exp type FilterMap map[string]*Exp
type Blacklist *regexp.Regexp type Blacklist map[string]struct{}
func CompileFilter(filter string) (*Exp, error) { func CompileFilter(filter string) (*Exp, error) {
node, err := ParseArgValue(filter) node, err := ParseArgValue(filter)
@ -194,7 +193,7 @@ func CompileFilter(filter string) (*Exp, error) {
type Compiler struct { type Compiler struct {
fm FilterMap fm FilterMap
bl *regexp.Regexp bl Blacklist
} }
func NewCompiler(fm FilterMap, bl Blacklist) *Compiler { func NewCompiler(fm FilterMap, bl Blacklist) *Compiler {
@ -231,7 +230,7 @@ func (com *Compiler) compileQuery(op *Operation) (*Query, error) {
st := util.NewStack() st := util.NewStack()
id := int16(0) id := int16(0)
fmap := make(map[*Field]*Select) fs := make([]*Select, op.FieldLen)
for i := range op.Fields { for i := range op.Fields {
st.Push(op.Fields[i]) st.Push(op.Fields[i])
@ -249,11 +248,10 @@ func (com *Compiler) compileQuery(op *Operation) (*Query, error) {
return nil, fmt.Errorf("unexpected value poped out %v", intf) return nil, fmt.Errorf("unexpected value poped out %v", intf)
} }
if com.bl != nil && com.bl.MatchString(field.Name) { fn := strings.ToLower(field.Name)
if _, ok := com.bl[fn]; ok {
continue continue
} }
fn := strings.ToLower(field.Name)
tn := flect.Pluralize(fn) tn := flect.Pluralize(fn)
s := &Select{ s := &Select{
@ -282,7 +280,7 @@ func (com *Compiler) compileQuery(op *Operation) (*Query, error) {
} }
id++ id++
fmap[field] = s fs[field.ID] = s
err := com.compileArgs(s, field.Args) err := com.compileArgs(s, field.Args)
if err != nil { if err != nil {
@ -293,7 +291,7 @@ func (com *Compiler) compileQuery(op *Operation) (*Query, error) {
f := field.Children[i] f := field.Children[i]
fn := strings.ToLower(f.Name) fn := strings.ToLower(f.Name)
if com.bl != nil && com.bl.MatchString(fn) { if _, ok := com.bl[fn]; ok {
continue continue
} }
@ -313,10 +311,9 @@ func (com *Compiler) compileQuery(op *Operation) (*Query, error) {
if field.Parent == nil { if field.Parent == nil {
selRoot = s selRoot = s
} else if sp, ok := fmap[field.Parent]; ok {
sp.Joins = append(sp.Joins, s)
} else { } else {
return nil, fmt.Errorf("no select found for parent %#v", field.Parent) sp := fs[field.Parent.ID]
sp.Joins = append(sp.Joins, s)
} }
} }
@ -333,14 +330,15 @@ func (com *Compiler) compileQuery(op *Operation) (*Query, error) {
func (com *Compiler) compileArgs(sel *Select, args []*Arg) error { func (com *Compiler) compileArgs(sel *Select, args []*Arg) error {
var err error var err error
ad := make(map[string]struct{})
sel.Args = make(map[string]*Node, len(args))
for i := range args { for i := range args {
if args[i] == nil { if args[i] == nil {
return fmt.Errorf("[Args] unexpected nil argument found") return fmt.Errorf("[Args] unexpected nil argument found")
} }
an := strings.ToLower(args[i].Name) an := strings.ToLower(args[i].Name)
if _, ok := ad[an]; ok { if _, ok := sel.Args[an]; ok {
continue continue
} }
@ -367,7 +365,7 @@ func (com *Compiler) compileArgs(sel *Select, args []*Arg) error {
return err return err
} }
ad[an] = struct{}{} sel.Args[an] = args[i].Val
} }
return nil return nil
@ -380,7 +378,7 @@ type expT struct {
func (com *Compiler) compileArgObj(arg *Arg) (*Exp, error) { func (com *Compiler) compileArgObj(arg *Arg) (*Exp, error) {
if arg.Val.Type != nodeObj { if arg.Val.Type != nodeObj {
return nil, fmt.Errorf("[Where] expecting an object") return nil, fmt.Errorf("expecting an object")
} }
return com.compileArgNode(arg.Val) return com.compileArgNode(arg.Val)
@ -400,12 +398,13 @@ func (com *Compiler) compileArgNode(val *Node) (*Exp, error) {
intf := st.Pop() intf := st.Pop()
eT, ok := intf.(*expT) eT, ok := intf.(*expT)
if !ok || eT == nil { if !ok || eT == nil {
return nil, fmt.Errorf("[Where] unexpected value poped out %v", intf) return nil, fmt.Errorf("unexpected value poped out %v", intf)
} }
if len(eT.node.Name) != 0 && if len(eT.node.Name) != 0 {
com.bl != nil && com.bl.MatchString(eT.node.Name) { if _, ok := com.bl[strings.ToLower(eT.node.Name)]; ok {
continue continue
}
} }
ex, err := newExp(st, eT) ex, err := newExp(st, eT)
@ -457,8 +456,6 @@ func (com *Compiler) compileArgSearch(sel *Select, arg *Arg) error {
Val: arg.Val.Val, Val: arg.Val.Val,
} }
sel.Args = append(sel.Args, arg)
if sel.Where != nil { if sel.Where != nil {
sel.Where = &Exp{Op: OpAnd, Children: []*Exp{ex, sel.Where}} sel.Where = &Exp{Op: OpAnd, Children: []*Exp{ex, sel.Where}}
} else { } else {
@ -507,7 +504,7 @@ func (com *Compiler) compileArgOrderBy(sel *Select, arg *Arg) error {
return fmt.Errorf("OrderBy: unexpected value poped out %v", intf) return fmt.Errorf("OrderBy: unexpected value poped out %v", intf)
} }
if com.bl != nil && com.bl.MatchString(node.Name) { if _, ok := com.bl[strings.ToLower(node.Name)]; ok {
continue continue
} }
@ -547,7 +544,7 @@ func (com *Compiler) compileArgOrderBy(sel *Select, arg *Arg) error {
func (com *Compiler) compileArgDistinctOn(sel *Select, arg *Arg) error { func (com *Compiler) compileArgDistinctOn(sel *Select, arg *Arg) error {
node := arg.Val node := arg.Val
if com.bl != nil && com.bl.MatchString(node.Name) { if _, ok := com.bl[strings.ToLower(node.Name)]; ok {
return nil return nil
} }

View File

@ -1,17 +1,14 @@
package qcode package qcode
import ( import (
"fmt"
"regexp"
"strings" "strings"
) )
func NewBlacklist(list []string) *regexp.Regexp { func NewBlacklist(list []string) Blacklist {
var bl *regexp.Regexp bl := make(map[string]struct{}, len(list))
if len(list) != 0 { for i := range list {
re := fmt.Sprintf("(?i)%s", strings.Join(list, "|")) bl[strings.ToLower(list[i])] = struct{}{}
bl = regexp.MustCompile(re)
} }
return bl return bl
} }