Skip to content

Commit

Permalink
feat: re-write of query introspection code
Browse files Browse the repository at this point in the history
- fixed a ton of bugs with the introspection result
- removed a library dependency we had with the previous introspection code
- added tons of new types to ensure our introspection result worked really well with query autocomplete ui's
  • Loading branch information
dosco committed Jan 12, 2023
1 parent ea999d4 commit 91722f9
Show file tree
Hide file tree
Showing 31 changed files with 1,477 additions and 1,173 deletions.
10 changes: 5 additions & 5 deletions core/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ type graphjin struct {
allowList *allow.List
encKey [32]byte
encKeySet bool
apq apqCache
cache Cache
queries sync.Map
roles map[string]*Role
roleStmt string
Expand Down Expand Up @@ -146,7 +146,7 @@ func newGraphJin(conf *Config,

// ordering of these initializer matter, do not re-order!

if err := gj.initAPQCache(); err != nil {
if err := gj.initCache(); err != nil {
return nil, err
}

Expand Down Expand Up @@ -293,7 +293,7 @@ func (g *GraphJin) GraphQL(c context.Context,

// get query from apq cache if apq key exists
if rc != nil && rc.APQKey != "" {
queryBytes, inCache = gj.apq.Get(rc.APQKey)
queryBytes, inCache = gj.cache.Get(rc.APQKey)
}

// query not found in apq cache so use original query
Expand Down Expand Up @@ -328,7 +328,7 @@ func (g *GraphJin) GraphQL(c context.Context,

// save to apq cache is apq key exists and not already in cache
if !inCache && rc != nil && rc.APQKey != "" {
gj.apq.Set(rc.APQKey, r.query)
gj.cache.Set(rc.APQKey, r.query)
}

// if not production then save to allow list
Expand Down Expand Up @@ -426,7 +426,7 @@ func (gj *graphjin) query(c context.Context, r graphqlReq) (
}

if !gj.prod && r.name == "IntrospectionQuery" {
resp.res.Data, err = gj.introspection(r.query)
resp.res.Data, err = gj.getIntroResult()
return
}

Expand Down
26 changes: 0 additions & 26 deletions core/apq.go

This file was deleted.

26 changes: 26 additions & 0 deletions core/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package core

import (
lru "github.com/hashicorp/golang-lru"
)

type Cache struct {
cache *lru.TwoQueueCache
}

func (gj *graphjin) initCache() (err error) {
gj.cache.cache, err = lru.New2Q(500)
return
}

func (c Cache) Get(key string) (val []byte, fromCache bool) {
if v, ok := c.cache.Get(key); ok {
val = v.([]byte)
fromCache = true
}
return
}

func (c Cache) Set(key string, val []byte) {
c.cache.Add(key, val)
}
13 changes: 13 additions & 0 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,19 @@ const (
// Duration time.Duration `json:"duration"`
// }

func (gj *graphjin) getIntroResult() (data json.RawMessage, err error) {
var ok bool
if data, ok = gj.cache.Get("_intro"); ok {
return
}
in := newIntro(gj.schema, gj.conf.EnableCamelcase)
if data, err = introspection(in); err != nil {
return
}
gj.cache.Set("_intro", data)
return
}

func (gj *graphjin) initDiscover() error {
switch gj.conf.DBType {
case "":
Expand Down
18 changes: 11 additions & 7 deletions core/internal/graph/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,17 +234,17 @@ func (p *Parser) parseFragment() (frag Fragment, err error) {
return frag, nil
}

func (p *Parser) parseOp() (Operation, error) {
var err error
var op Operation

func (p *Parser) parseOp() (op Operation, err error) {
s := p.curr().pos + 1

if !p.peekVal(queryToken, mutationToken, subscriptionToken) {
return op, fmt.Errorf("expecting a query, mutation or subscription, got: %s", p.peekNext())
if p.peekVal(queryToken, mutationToken, subscriptionToken) {
err = p.parseOpTypeAndArgs(&op)

} else if !p.peek(itemObjOpen) {
err = p.tokErr(`query, mutation or subscription`)
}

if err = p.parseOpTypeAndArgs(&op); err != nil {
if err != nil {
return op, fmt.Errorf("%s: %v", op.Type, err)
}

Expand All @@ -253,6 +253,10 @@ func (p *Parser) parseOp() (Operation, error) {
}
p.ignore()

if op.Type == 0 {
op.Type = OpQuery
}

op.Fields, err = p.parseFields(op.Fields)
if err != nil {
return op, fmt.Errorf("%s: %v", op.Type, err)
Expand Down
2 changes: 1 addition & 1 deletion core/internal/psql/insert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func singleInsert(t *testing.T) {

func bulkInsert(t *testing.T) {
gql := `mutation {
products(name: "test", id: $id, insert: $insert) {
products(id: $id, insert: $insert) {
id
name
}
Expand Down
38 changes: 19 additions & 19 deletions core/internal/qcode/exp.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,79 +298,79 @@ func (ast *aexpst) processOpAndVal(av aexp, ex *Exp, node *graph.Node) (bool, er
case "eq", "equals":
ex.Op = OpEquals
ex.Right.Val = node.Val
case "neq", "not_equals":
case "neq", "notEquals", "not_equals":
ex.Op = OpNotEquals
ex.Right.Val = node.Val
case "gt", "greater_than":
case "gt", "greaterThan", "greater_than":
ex.Op = OpGreaterThan
ex.Right.Val = node.Val
case "lt", "lesser_than":
case "lt", "lesserThan", "lesser_than":
ex.Op = OpLesserThan
ex.Right.Val = node.Val
case "gte", "gteq", "greater_or_equals":
case "gte", "gteq", "greaterOrEquals", "greater_or_equals":
ex.Op = OpGreaterOrEquals
ex.Right.Val = node.Val
case "lte", "lteq", "lesser_or_equals":
case "lte", "lteq", "lesserOrEquals", "lesser_or_equals":
ex.Op = OpLesserOrEquals
ex.Right.Val = node.Val
case "in":
ex.Op = OpIn
setListVal(ex, node)
case "nin", "not_in":
case "nin", "notIn", "not_in":
ex.Op = OpNotIn
setListVal(ex, node)
case "like":
ex.Op = OpLike
ex.Right.Val = node.Val
case "nlike", "not_like":
case "nlike", "notLike", "not_like":
ex.Op = OpNotLike
ex.Right.Val = node.Val
case "ilike":
case "ilike", "iLike":
ex.Op = OpILike
ex.Right.Val = node.Val
case "nilike", "not_ilike":
case "nilike", "notILike", "not_ilike":
ex.Op = OpNotILike
ex.Right.Val = node.Val
case "similar":
ex.Op = OpSimilar
ex.Right.Val = node.Val
case "nsimilar", "not_similar":
case "nsimilar", "notSimiliar", "not_similar":
ex.Op = OpNotSimilar
ex.Right.Val = node.Val
case "regex":
ex.Op = OpRegex
ex.Right.Val = node.Val
case "nregex", "not_regex":
case "nregex", "notRegex", "not_regex":
ex.Op = OpNotRegex
ex.Right.Val = node.Val
case "iregex":
ex.Op = OpIRegex
ex.Right.Val = node.Val
case "niregex", "not_iregex":
case "niregex", "notIRegex", "not_iregex":
ex.Op = OpNotIRegex
ex.Right.Val = node.Val
case "contains":
ex.Op = OpContains
setListVal(ex, node)
case "contained_in":
case "containedIn", "contained_in":
ex.Op = OpContainedIn
setListVal(ex, node)
case "has_in_common":
case "hasInCommon", "has_in_common":
ex.Op = OpHasInCommon
setListVal(ex, node)
case "has_key":
case "hasKey", "has_key":
ex.Op = OpHasKey
ex.Right.Val = node.Val
case "has_key_any":
case "hasKeyAny", "has_key_any":
ex.Op = OpHasKeyAny
setListVal(ex, node)
case "has_key_all":
case "hasKeyAll", "has_key_all":
ex.Op = OpHasKeyAll
setListVal(ex, node)
case "is_null":
case "isNull", "is_null":
ex.Op = OpIsNull
ex.Right.Val = node.Val
case "ndis", "not_distinct":
case "notDistinct", "ndis", "not_distinct":
ex.Op = OpNotDistinct
ex.Right.Val = node.Val
case "dis", "distinct":
Expand Down
Loading

1 comment on commit 91722f9

@vercel
Copy link

@vercel vercel bot commented on 91722f9 Jan 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.