super-graph/core/internal/psql/query_test.go

573 lines
8.4 KiB
Go
Raw Normal View History

package psql_test
2019-03-24 14:57:29 +01:00
import (
2019-06-02 01:48:42 +02:00
"bytes"
"encoding/json"
2019-03-24 14:57:29 +01:00
"testing"
)
func withComplexArgs(t *testing.T) {
2019-03-24 23:16:03 +01:00
gql := `query {
2019-06-15 04:17:21 +02:00
proDUcts(
2019-03-24 23:16:03 +01:00
# returns only 30 items
limit: 30,
2020-02-10 07:45:37 +01:00
2019-03-24 23:16:03 +01:00
# starts from item 10, commented out for now
# offset: 10,
2020-02-10 07:45:37 +01:00
2019-03-24 23:16:03 +01:00
# orders the response items by highest price
order_by: { price: desc },
2020-02-10 07:45:37 +01:00
2019-03-24 23:16:03 +01:00
# no duplicate prices returned
distinct: [ price ]
2020-02-10 07:45:37 +01:00
2019-10-03 09:08:01 +02:00
# only items with an id >= 20 and < 28 are returned
2019-03-24 23:16:03 +01:00
where: { id: { and: { greater_or_equals: 20, lt: 28 } } }) {
id
2019-06-15 04:17:21 +02:00
NAME
2019-03-24 23:16:03 +01:00
price
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
}
func withWhereIn(t *testing.T) {
gql := `query {
products(where: { id: { in: $list } }) {
id
}
}`
vars := map[string]json.RawMessage{
"list": json.RawMessage(`[1,2,3]`),
}
compileGQLToPSQL(t, gql, vars, "user")
}
2020-02-10 07:45:37 +01:00
func withWhereAndList(t *testing.T) {
gql := `query {
products(
where: {
2020-02-10 07:45:37 +01:00
and: [
{ not: { id: { is_null: true } } },
{ price: { gt: 10 } },
] } ) {
id
name
price
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
}
func withWhereIsNull(t *testing.T) {
gql := `query {
products(
where: {
and: {
not: { id: { is_null: true } },
price: { gt: 10 }
}}) {
id
name
price
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
}
2020-02-10 07:45:37 +01:00
func withWhereMultiOr(t *testing.T) {
gql := `query {
products(
where: {
2020-02-10 07:45:37 +01:00
or: {
not: { id: { is_null: true } },
price: { gt: 10 },
price: { lt: 20 }
} }
) {
id
name
price
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
2019-03-24 23:16:03 +01:00
}
func fetchByID(t *testing.T) {
2019-03-24 23:16:03 +01:00
gql := `query {
product(id: $id) {
id
name
2019-03-24 23:16:03 +01:00
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
2019-03-24 23:16:03 +01:00
}
func searchQuery(t *testing.T) {
2019-03-24 23:16:03 +01:00
gql := `query {
products(search: $query) {
id
2019-03-24 23:16:03 +01:00
name
search_rank
search_headline_description
2019-03-24 23:16:03 +01:00
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "admin")
2019-03-24 23:16:03 +01:00
}
func oneToMany(t *testing.T) {
gql := `query {
users {
email
products {
name
price
2019-03-24 23:16:03 +01:00
}
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
2019-03-24 23:16:03 +01:00
}
func oneToManyReverse(t *testing.T) {
2019-03-24 23:16:03 +01:00
gql := `query {
products {
name
price
users {
email
2019-03-24 23:16:03 +01:00
}
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
2019-03-24 14:57:29 +01:00
}
2019-03-25 04:42:54 +01:00
func oneToManyArray(t *testing.T) {
2020-01-16 07:44:19 +01:00
gql := `
query {
product {
name
price
tags {
id
name
}
2020-01-16 07:44:19 +01:00
}
tags {
name
product {
name
}
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "admin")
}
func manyToMany(t *testing.T) {
2019-04-04 06:53:24 +02:00
gql := `query {
products {
2019-04-04 06:53:24 +02:00
name
customers {
email
full_name
}
2019-04-04 06:53:24 +02:00
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
2019-04-04 06:53:24 +02:00
}
func manyToManyReverse(t *testing.T) {
gql := `query {
customers {
email
full_name
products {
name
}
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
}
func aggFunction(t *testing.T) {
gql := `query {
products {
name
count_price
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
2019-10-14 08:51:36 +02:00
}
func aggFunctionBlockedByCol(t *testing.T) {
gql := `query {
products {
name
count_price
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "anon")
2019-10-14 08:51:36 +02:00
}
func aggFunctionDisabled(t *testing.T) {
gql := `query {
products {
name
count_price
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "anon1")
}
func aggFunctionWithFilter(t *testing.T) {
gql := `query {
products(where: { id: { gt: 10 } }) {
id
max_price
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
2019-04-09 03:24:29 +02:00
}
func syntheticTables(t *testing.T) {
gql := `query {
me {
email
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
}
2019-04-20 06:35:57 +02:00
func queryWithVariables(t *testing.T) {
gql := `query {
product(id: $PRODUCT_ID, where: { price: { eq: $PRODUCT_PRICE } }) {
id
name
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
2019-04-20 06:35:57 +02:00
}
func withWhereOnRelations(t *testing.T) {
2019-04-09 03:24:29 +02:00
gql := `query {
users(where: {
not: {
products: {
2020-01-13 15:34:15 +01:00
price: { gt: 3 }
}
}
}) {
id
2019-04-09 03:24:29 +02:00
email
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
2019-11-19 06:47:55 +01:00
}
func multiRoot(t *testing.T) {
gql := `query {
product {
id
name
customer {
email
}
customers {
email
}
}
user {
id
email
}
customer {
id
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "user")
}
func withFragment1(t *testing.T) {
gql := `
fragment userFields1 on user {
id
email
}
query {
users {
...userFields2
created_at
...userFields1
}
}
fragment userFields2 on user {
first_name
last_name
}`
compileGQLToPSQL(t, gql, nil, "anon")
}
func withFragment2(t *testing.T) {
gql := `
query {
users {
...userFields2
created_at
...userFields1
}
}
fragment userFields1 on user {
id
email
}
fragment userFields2 on user {
first_name
last_name
}`
compileGQLToPSQL(t, gql, nil, "anon")
}
func withFragment3(t *testing.T) {
gql := `
fragment userFields1 on user {
id
email
}
fragment userFields2 on user {
first_name
last_name
}
query {
users {
...userFields2
created_at
...userFields1
}
}
`
compileGQLToPSQL(t, gql, nil, "anon")
}
// func withInlineFragment(t *testing.T) {
// gql := `
// query {
// users {
// ... on users {
// id
// email
// }
// created_at
// ... on user {
// first_name
// last_name
// }
// }
// }
// `
// compileGQLToPSQL(t, gql, nil, "anon")
// }
2020-06-09 08:13:51 +02:00
func withCursor(t *testing.T) {
gql := `query {
Products(
first: 20
after: $cursor
order_by: { price: desc }) {
Name
}
}`
vars := map[string]json.RawMessage{
"cursor": json.RawMessage(`"0,1"`),
}
compileGQLToPSQL(t, gql, vars, "admin")
}
func jsonColumnAsTable(t *testing.T) {
gql := `query {
products {
id
name
tag_count {
count
tags {
name
}
}
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "admin")
}
2020-03-14 06:35:42 +01:00
func nullForAuthRequiredInAnon(t *testing.T) {
gql := `query {
products {
id
name
user(where: { id: { eq: $user_id } }) {
id
email
}
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "anon")
}
func blockedQuery(t *testing.T) {
gql := `query {
user(id: $id, where: { id: { gt: 3 } }) {
id
full_name
email
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "bad_dude")
}
func blockedFunctions(t *testing.T) {
gql := `query {
users {
count_id
email
}
}`
2020-02-10 07:45:37 +01:00
compileGQLToPSQL(t, gql, nil, "bad_dude")
}
2019-10-14 08:51:36 +02:00
func TestCompileQuery(t *testing.T) {
t.Run("withComplexArgs", withComplexArgs)
t.Run("withWhereIn", withWhereIn)
t.Run("withWhereAndList", withWhereAndList)
t.Run("withWhereIsNull", withWhereIsNull)
t.Run("withWhereMultiOr", withWhereMultiOr)
2019-04-04 06:53:24 +02:00
t.Run("fetchByID", fetchByID)
t.Run("searchQuery", searchQuery)
t.Run("oneToMany", oneToMany)
t.Run("oneToManyReverse", oneToManyReverse)
t.Run("oneToManyArray", oneToManyArray)
t.Run("manyToMany", manyToMany)
t.Run("manyToManyReverse", manyToManyReverse)
t.Run("aggFunction", aggFunction)
2019-10-14 08:51:36 +02:00
t.Run("aggFunctionBlockedByCol", aggFunctionBlockedByCol)
t.Run("aggFunctionDisabled", aggFunctionDisabled)
t.Run("aggFunctionWithFilter", aggFunctionWithFilter)
2019-04-09 03:24:29 +02:00
t.Run("syntheticTables", syntheticTables)
2019-10-03 09:08:01 +02:00
t.Run("queryWithVariables", queryWithVariables)
t.Run("withWhereOnRelations", withWhereOnRelations)
2019-11-19 06:47:55 +01:00
t.Run("multiRoot", multiRoot)
t.Run("withFragment1", withFragment1)
t.Run("withFragment2", withFragment2)
t.Run("withFragment3", withFragment3)
//t.Run("withInlineFragment", withInlineFragment)
t.Run("jsonColumnAsTable", jsonColumnAsTable)
t.Run("withCursor", withCursor)
2020-03-14 06:35:42 +01:00
t.Run("nullForAuthRequiredInAnon", nullForAuthRequiredInAnon)
t.Run("blockedQuery", blockedQuery)
t.Run("blockedFunctions", blockedFunctions)
}
2019-06-15 04:17:21 +02:00
var benchGQL = []byte(`query {
proDUcts(
# returns only 30 items
limit: 30,
# starts from item 10, commented out for now
# offset: 10,
# orders the response items by highest price
order_by: { price: desc },
# only items with an id >= 30 and < 30 are returned
where: { id: { and: { greater_or_equals: 20, lt: 28 } } }) {
id
2019-06-15 04:17:21 +02:00
NAME
price
user {
full_name
picture : avatar
2019-03-25 04:42:54 +01:00
}
}
2019-06-15 04:17:21 +02:00
}`)
2019-03-25 04:42:54 +01:00
func BenchmarkCompile(b *testing.B) {
w := &bytes.Buffer{}
2019-06-02 01:48:42 +02:00
2019-03-25 04:42:54 +01:00
b.ResetTimer()
b.ReportAllocs()
for n := 0; n < b.N; n++ {
w.Reset()
2019-10-14 08:51:36 +02:00
qc, err := qcompile.Compile(benchGQL, "user")
2019-06-02 01:48:42 +02:00
if err != nil {
b.Fatal(err)
}
_, err = pcompile.Compile(w, qc, nil)
2019-03-25 04:42:54 +01:00
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkCompileParallel(b *testing.B) {
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
w := &bytes.Buffer{}
for pb.Next() {
w.Reset()
2019-10-14 08:51:36 +02:00
qc, err := qcompile.Compile(benchGQL, "user")
if err != nil {
b.Fatal(err)
}
_, err = pcompile.Compile(w, qc, nil)
if err != nil {
b.Fatal(err)
}
}
})
}