Add corrupt query validation
This commit is contained in:
parent
7240b27214
commit
e3c94d17d1
|
@ -209,7 +209,8 @@ func oneToManyReverse(t *testing.T) {
|
|||
}
|
||||
|
||||
func oneToManyArray(t *testing.T) {
|
||||
gql := `query {
|
||||
gql := `
|
||||
query {
|
||||
product {
|
||||
name
|
||||
price
|
||||
|
@ -224,7 +225,6 @@ func oneToManyArray(t *testing.T) {
|
|||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
sql := `SELECT row_to_json("json_root") FROM (SELECT "sel_0"."json_0" AS "tags", "sel_2"."json_2" AS "product" FROM (SELECT row_to_json((SELECT "json_row_2" FROM (SELECT "products_2"."name" AS "name", "products_2"."price" AS "price", "tags_3_join"."json_3" AS "tags") AS "json_row_2")) AS "json_2" FROM (SELECT "products"."name", "products"."price", "products"."tags" FROM "products" LIMIT ('1') :: integer) AS "products_2" LEFT OUTER JOIN LATERAL (SELECT coalesce(json_agg("json_3"), '[]') AS "json_3" FROM (SELECT row_to_json((SELECT "json_row_3" FROM (SELECT "tags_3"."id" AS "id", "tags_3"."name" AS "name") AS "json_row_3")) AS "json_3" FROM (SELECT "tags"."id", "tags"."name" FROM "tags" WHERE ((("tags"."slug") = any ("products_2"."tags"))) LIMIT ('20') :: integer) AS "tags_3" LIMIT ('20') :: integer) AS "json_agg_3") AS "tags_3_join" ON ('true') LIMIT ('1') :: integer) AS "sel_2", (SELECT coalesce(json_agg("json_0"), '[]') AS "json_0" FROM (SELECT row_to_json((SELECT "json_row_0" FROM (SELECT "tags_0"."name" AS "name", "product_1_join"."json_1" AS "product") AS "json_row_0")) AS "json_0" FROM (SELECT "tags"."name", "tags"."slug" FROM "tags" LIMIT ('20') :: integer) AS "tags_0" LEFT OUTER JOIN LATERAL (SELECT row_to_json((SELECT "json_row_1" FROM (SELECT "products_1"."name" AS "name") AS "json_row_1")) AS "json_1" FROM (SELECT "products"."name" FROM "products" WHERE ((("tags_0"."slug") = any ("products"."tags"))) LIMIT ('1') :: integer) AS "products_1" LIMIT ('1') :: integer) AS "product_1_join" ON ('true') LIMIT ('20') :: integer) AS "json_agg_0") AS "sel_0") AS "json_root"`
|
||||
|
|
13
qcode/lex.go
13
qcode/lex.go
|
@ -31,7 +31,7 @@ type item struct {
|
|||
_type itemType // The type of this item.
|
||||
pos Pos // The starting position, in bytes, of this item in the input string.
|
||||
end Pos // The ending position, in bytes, of this item in the input string.
|
||||
line uint16 // The line number at the start of this item.
|
||||
line int16 // The line number at the start of this item.
|
||||
}
|
||||
|
||||
// itemType identifies the type of lex items.
|
||||
|
@ -87,7 +87,7 @@ type lexer struct {
|
|||
width Pos // width of last rune read from input
|
||||
items []item // array of scanned items
|
||||
itemsA [50]item
|
||||
line uint16 // 1+number of newlines seen
|
||||
line int16 // 1+number of newlines seen
|
||||
err error
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,7 @@ func (l *lexer) emit(t itemType) {
|
|||
l.items = append(l.items, item{t, l.start, l.pos, l.line})
|
||||
// Some items contain text internally. If so, count their newlines.
|
||||
switch t {
|
||||
case itemName:
|
||||
case itemStringVal:
|
||||
for i := l.start; i < l.pos; i++ {
|
||||
if l.input[i] == '\n' {
|
||||
l.line++
|
||||
|
@ -155,11 +155,6 @@ func (l *lexer) emitL(t itemType) {
|
|||
|
||||
// ignore skips over the pending input before this point.
|
||||
func (l *lexer) ignore() {
|
||||
for i := l.start; i < l.pos; i++ {
|
||||
if l.input[i] == '\n' {
|
||||
l.line++
|
||||
}
|
||||
}
|
||||
l.start = l.pos
|
||||
}
|
||||
|
||||
|
@ -436,7 +431,7 @@ func lowercase(b []byte, s Pos, e Pos) {
|
|||
}
|
||||
}
|
||||
|
||||
func (i *item) String() string {
|
||||
func (i item) String() string {
|
||||
var v string
|
||||
|
||||
switch i._type {
|
||||
|
|
|
@ -156,12 +156,24 @@ func parseSelectionSet(gql []byte) (*Operation, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
lexPool.Put(l)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if p.peek(itemObjClose) {
|
||||
p.ignore()
|
||||
} else {
|
||||
return nil, fmt.Errorf("operation missing closing '}'")
|
||||
}
|
||||
|
||||
if !p.peek(itemEOF) {
|
||||
p.ignore()
|
||||
return nil, fmt.Errorf("invalid '%s' found after closing '}'", p.current())
|
||||
}
|
||||
|
||||
// for i := p.pos; i < len(p.items); i++ {
|
||||
// fmt.Printf("2>>>> %#v\n", p.items[i])
|
||||
// }
|
||||
//return nil, fmt.Errorf("unexpected token")
|
||||
|
||||
lexPool.Put(l)
|
||||
|
||||
return op, err
|
||||
}
|
||||
|
||||
|
@ -184,11 +196,16 @@ func (p *Parser) ignore() {
|
|||
p.pos = n
|
||||
}
|
||||
|
||||
func (p *Parser) current() string {
|
||||
item := p.items[p.pos]
|
||||
return b2s(p.input[item.pos:item.end])
|
||||
}
|
||||
|
||||
func (p *Parser) peek(types ...itemType) bool {
|
||||
n := p.pos + 1
|
||||
if p.items[n]._type == itemEOF {
|
||||
return false
|
||||
}
|
||||
// if p.items[n]._type == itemEOF {
|
||||
// return false
|
||||
// }
|
||||
if n >= len(p.items) {
|
||||
return false
|
||||
}
|
||||
|
@ -292,9 +309,10 @@ func (p *Parser) parseFields(fields []Field) ([]Field, error) {
|
|||
|
||||
if st.Len() == 0 {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if !p.peek(itemName) {
|
||||
return nil, errors.New("expecting an alias or field name")
|
||||
|
@ -306,6 +324,8 @@ func (p *Parser) parseFields(fields []Field) ([]Field, error) {
|
|||
f.Args = f.argsA[:0]
|
||||
f.Children = f.childrenA[:0]
|
||||
|
||||
// Parse the inside of the the fields () parentheses
|
||||
// in short parse the args like id, where, etc
|
||||
if err := p.parseField(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -318,6 +338,8 @@ func (p *Parser) parseFields(fields []Field) ([]Field, error) {
|
|||
f.ParentID = -1
|
||||
}
|
||||
|
||||
// The first opening curley brackets after this
|
||||
// comes the columns or child fields
|
||||
if p.peek(itemObjOpen) {
|
||||
p.ignore()
|
||||
st.Push(f.ID)
|
||||
|
|
|
@ -17,7 +17,7 @@ func TestCompile1(t *testing.T) {
|
|||
}
|
||||
|
||||
_, err = qc.Compile([]byte(`
|
||||
{ product(id: 15) {
|
||||
query { product(id: 15) {
|
||||
id
|
||||
name
|
||||
} }`), "user")
|
||||
|
@ -100,6 +100,35 @@ func TestEmptyCompile(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestInvalidPostfixCompile(t *testing.T) {
|
||||
gql := `mutation
|
||||
updateThread {
|
||||
thread(update: $data, where: { slug: { eq: $slug } }) {
|
||||
slug
|
||||
title
|
||||
published
|
||||
createdAt : created_at
|
||||
totalVotes : cached_votes_total
|
||||
totalPosts : cached_posts_total
|
||||
vote : thread_vote(where: { user_id: { eq: $user_id } }) {
|
||||
id
|
||||
}
|
||||
topics {
|
||||
slug
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
qcompile, _ := NewCompiler(Config{})
|
||||
_, err := qcompile.Compile([]byte(gql), "anon")
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(errors.New("expecting an error"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var gql = []byte(`
|
||||
products(
|
||||
# returns only 30 items
|
||||
|
|
Loading…
Reference in New Issue