Documentation
¶
Overview ¶
Package core provides an API to include and use the GraphJin compiler with your own code. For detailed documentation visit https://graphjin.com
Example usage:
package main
import (
"database/sql"
"fmt"
"time"
"github.com/dosco/graphjin/core"
_ "github.com/jackc/pgx/v5/stdlib"
)
func main() {
db, err := sql.Open("pgx", "postgres://postgrs:@localhost:5432/example_db")
if err != nil {
log.Fatal(err)
}
gj, err := core.NewGraphJin(nil, db)
if err != nil {
log.Fatal(err)
}
query := `
query {
posts {
id
title
}
}`
ctx = context.WithValue(ctx, core.UserIDKey, 1)
res, err := gj.GraphQL(ctx, query, nil)
if err != nil {
log.Fatal(err)
}
}
Example (Insert) ¶
gql := `mutation {
users(insert: $data) {
id
email
}
}`
vars := json.RawMessage(`{
"data": {
"id": 1001,
"email": "[email protected]",
"full_name": "User 1001",
"stripe_id": "payment_id_1001",
"category_counts": [{"category_id": 1, "count": 400},{"category_id": 2, "count": 600}]
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":[{"email":"[email protected]","id":1001}]}
Example (InsertBulk) ¶
gql := `mutation {
users(insert: $data) {
id
email
}
}`
vars := json.RawMessage(`{
"data": [{
"id": 1002,
"email": "[email protected]",
"full_name": "User 1002",
"stripe_id": "payment_id_1002",
"category_counts": [{"category_id": 1, "count": 400},{"category_id": 2, "count": 600}]
},
{
"id": 1003,
"email": "[email protected]",
"full_name": "User 1003",
"stripe_id": "payment_id_1003",
"category_counts": [{"category_id": 2, "count": 400},{"category_id": 3, "count": 600}]
}]
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":[{"email":"[email protected]","id":1002},{"email":"[email protected]","id":1003}]}
Example (InsertInline) ¶
gql := `mutation {
users(insert: { id: $id, email: $email, full_name: $full_name }) {
id
email
full_name
}
}`
vars := json.RawMessage(`{
"id": 1007,
"email": "[email protected]",
"full_name": "User 1007"
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":[{"email":"[email protected]","full_name":"User 1007","id":1007}]}
Example (InsertInlineBulk) ¶
gql := `mutation {
users(insert: [
{id: $id1, email: $email1, full_name: $full_name1},
{id:, $id2, email: $email2, full_name: $full_name2}]) {
id
email
}
}`
vars := json.RawMessage(`{
"id1": 1008,
"email1": "[email protected]",
"full_name1": "John One",
"id2": 1009,
"email2": "[email protected]",
"full_name2": "John Two"
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":[{"email":"[email protected]","id":1009},{"email":"[email protected]","id":1008}]}
Example (InsertInlineWithValidation) ¶
gql := `mutation
@constraint(variable: "email", format: "email", min: 1, max: 100)
@constraint(variable: "full_name", requiredIf: { id: 1007 } ) {
users(insert: { id: $id, email: $email, full_name: $full_name }) {
id
email
full_name
}
}`
vars := json.RawMessage(`{
"id": 1007,
"email": "not_an_email"
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: Validation Failed: $full_name: Key: '' Error:Field validation for '' failed on the 'required_if' tag Validation Failed: $email: Key: '' Error:Field validation for '' failed on the 'email' tag validation failed
Example (InsertIntoMultipleRelatedTables) ¶
gql := `mutation {
purchases(insert: $data) {
quantity
customer {
id
full_name
email
}
product {
id
name
price
}
}
}`
vars := json.RawMessage(`{
"data": {
"id": 3001,
"quantity": 5,
"customer": {
"id": 1004,
"email": "[email protected]",
"full_name": "User 1004",
"stripe_id": "payment_id_1004",
"category_counts": [{"category_id": 1, "count": 400},{"category_id": 2, "count": 600}]
},
"product": {
"id": 2002,
"name": "Product 2002",
"description": "Description for product 2002",
"price": 2012.5,
"tags": ["Tag 1", "Tag 2"],
"category_ids": [1, 2, 3, 4, 5],
"owner_id": 3
}
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"purchases":[{"customer":{"email":"[email protected]","full_name":"User 1004","id":1004},"product":{"id":2002,"name":"Product 2002","price":2012.5},"quantity":5}]}
Example (InsertIntoRecursiveRelationship) ¶
gql := `mutation {
comments(insert: $data, where: { id: { in: [5001, 5002] }}) {
id
reply_to_id
}
}`
vars := json.RawMessage(`{
"data": {
"id": 5001,
"body": "Comment body 5001",
"created_at": "now",
"comments": {
"find": "children",
"id": 5002,
"body": "Comment body 5002",
"created_at": "now"
}
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"comments":[{"id":5001,"reply_to_id":null},{"id":5002,"reply_to_id":5001}]}
Example (InsertIntoRecursiveRelationshipAndConnectTable1) ¶
gql := `mutation {
comments(insert: $data, where: { id: { in: [5, 5003] }}) {
id
reply_to_id
}
}`
vars := json.RawMessage(`{
"data": {
"id": 5003,
"body": "Comment body 5003",
"created_at": "now",
"comments": {
"find": "children",
"connect": { "id": 5 }
}
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"comments":[{"id":5003,"reply_to_id":null},{"id":5,"reply_to_id":5003}]}
Example (InsertIntoRecursiveRelationshipAndConnectTable2) ¶
gql := `mutation {
comments(insert: $data) @object {
id
product {
id
}
commenter {
id
}
comments(find: "children") {
id
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
vars := json.RawMessage(`{
"data": {
"id": 5004,
"body": "Comment body 5004",
"created_at": "now",
"comments": {
"connect": { "id": 6 },
"find": "children"
},
"product": {
"connect": { "id": 26 }
},
"commenter":{
"connect":{ "id": 3 }
}
}
}`)
ctx := context.WithValue(context.Background(), core.UserIDKey, 50)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"comments":{"commenter":{"id":3},"comments":[{"id":6}],"id":5004,"product":{"id":26}}}
Example (InsertIntoTableAndConnectToRelatedTableWithArrayColumn) ¶
gql := `mutation {
products(insert: $data) {
id
name
categories {
id
name
}
}
}`
vars := json.RawMessage(`{
"data": {
"id": 2006,
"name": "Product 2006",
"description": "Description for product 2006",
"price": 2016.5,
"tags": ["Tag 1", "Tag 2"],
"categories": {
"connect": { "id": [1, 2, 3, 4, 5] }
}
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
conf.Tables = []core.Table{
{Name: "products", Columns: []core.Column{{Name: "category_ids", ForeignKey: "categories.id"}}},
}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"categories":[{"id":1,"name":"Category 1"},{"id":2,"name":"Category 2"},{"id":3,"name":"Category 3"},{"id":4,"name":"Category 4"},{"id":5,"name":"Category 5"}],"id":2006,"name":"Product 2006"}]}
Example (InsertIntoTableAndConnectToRelatedTables) ¶
gql := `mutation {
products(insert: $data) {
id
name
owner {
id
full_name
email
}
}
}`
vars := json.RawMessage(`{
"data": {
"id": 2005,
"name": "Product 2005",
"description": "Description for product 2005",
"price": 2015.5,
"tags": ["Tag 1", "Tag 2"],
"category_ids": [1, 2, 3, 4, 5],
"owner": {
"connect": { "id": 6 }
}
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":2005,"name":"Product 2005","owner":{"email":"[email protected]","full_name":"User 6","id":6}}]}
Example (InsertIntoTableAndRelatedTable1) ¶
gql := `mutation {
users(insert: $data) {
id
full_name
email
products {
id
name
price
}
}
}`
vars := json.RawMessage(`{
"data": {
"id": 1005,
"email": "[email protected]",
"full_name": "User 1005",
"stripe_id": "payment_id_1005",
"category_counts": [{"category_id": 1, "count": 400},{"category_id": 2, "count": 600}],
"products": {
"id": 2003,
"name": "Product 2003",
"description": "Description for product 2003",
"price": 2013.5,
"tags": ["Tag 1", "Tag 2"],
"category_ids": [1, 2, 3, 4, 5],
"owner_id": 3
}
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":[{"email":"[email protected]","full_name":"User 1005","id":1005,"products":[{"id":2003,"name":"Product 2003","price":2013.5}]}]}
Example (InsertIntoTableAndRelatedTable2) ¶
gql := `mutation {
products(insert: $data) {
id
name
owner {
id
full_name
email
}
}
}`
vars := json.RawMessage(`{
"data": {
"id": 2004,
"name": "Product 2004",
"description": "Description for product 2004",
"price": 2014.5,
"tags": ["Tag 1", "Tag 2"],
"category_ids": [1, 2, 3, 4, 5],
"owner": {
"id": 1006,
"email": "[email protected]",
"full_name": "User 1006",
"stripe_id": "payment_id_1006",
"category_counts": [{"category_id": 1, "count": 400},{"category_id": 2, "count": 600}]
}
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":2004,"name":"Product 2004","owner":{"email":"[email protected]","full_name":"User 1006","id":1006}}]}
Example (InsertIntoTableBulkInsertIntoRelatedTable) ¶
gql := `mutation {
users(insert: $data) {
id
full_name
email
products {
id
name
price
}
}
}`
vars := json.RawMessage(`{
"data": {
"id": 10051,
"email": "[email protected]",
"full_name": "User 10051",
"stripe_id": "payment_id_10051",
"category_counts": [
{"category_id": 1, "count": 400},
{"category_id": 2, "count": 600}
],
"products": [
{
"id": 20031,
"name": "Product 20031",
"description": "Description for product 20031",
"price": 2013.5,
"tags": ["Tag 1", "Tag 2"],
"category_ids": [1, 2, 3, 4, 5],
"owner_id": 3
},
{
"id": 20032,
"name": "Product 20032",
"description": "Description for product 20032",
"price": 2014.5,
"tags": ["Tag 1", "Tag 2"],
"category_ids": [1, 2, 3, 4, 5],
"owner_id": 3
}
]
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":[{"email":"[email protected]","full_name":"User 10051","id":10051,"products":[{"id":20031,"name":"Product 20031","price":2013.5},{"id":20032,"name":"Product 20032","price":2014.5}]}]}
Example (InsertWithCamelToSnakeCase) ¶
gql := `mutation {
products(insert: $data) {
id
name
owner {
id
email
}
}
}`
vars := json.RawMessage(`{
"data": {
"id": 2007,
"name": "Product 2007",
"description": "Description for product 2007",
"price": 2011.5,
"tags": ["Tag 1", "Tag 2"],
"categoryIds": [1, 2, 3, 4, 5]
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, EnableCamelcase: true})
err := conf.AddRoleTable("user", "products", core.Insert{
Presets: map[string]string{"ownerId": "$user_id"},
})
if err != nil {
panic(err)
}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":2007,"name":"Product 2007","owner":{"email":"[email protected]","id":3}}]}
Example (InsertWithPresets) ¶
gql := `mutation {
products(insert: $data) {
id
name
owner {
id
email
}
}
}`
vars := json.RawMessage(`{
"data": {
"id": 2001,
"name": "Product 2001",
"description": "Description for product 2001",
"price": 2011.5,
"tags": ["Tag 1", "Tag 2"],
"category_ids": [1, 2, 3, 4, 5]
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
err := conf.AddRoleTable("user", "products", core.Insert{
Presets: map[string]string{"owner_id": "$user_id"},
})
if err != nil {
panic(err)
}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":2001,"name":"Product 2001","owner":{"email":"[email protected]","id":3}}]}
Example (Query) ¶
gql := `
query {
products(limit: 3) {
id
owner {
id
fullName: full_name
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":1,"owner":{"fullName":"User 1","id":1}},{"id":2,"owner":{"fullName":"User 2","id":2}},{"id":3,"owner":{"fullName":"User 3","id":3}}]}
Example (QueryBlockWithRoles) ¶
gql := `query {
users {
id
full_name
email
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
conf.RolesQuery = `SELECT * FROM users WHERE id = $user_id`
conf.Roles = []core.Role{{Name: "disabled_user", Match: "disabled = true"}}
err := conf.AddRoleTable("disabled_user", "users", core.Query{Block: true})
if err != nil {
panic(err)
}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 50)
res, err := gj.GraphQL(ctx, gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":null}
Example (QueryByID) ¶
gql := `query {
products(id: $id) {
id
name
}
}`
vars := json.RawMessage(`{
"id": 2
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":{"id":2,"name":"Product 2"}}
Example (QueryBySearch) ¶
gql := `query {
products(search: $query, limit: 5) {
id
name
}
}`
vars := json.RawMessage(`{
"query": "\"Product 3\""
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":3,"name":"Product 3"}]}
Example (QueryChildrenWithParent) ¶
gql := `query {
products(limit: 2) {
name
price
owner {
email
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"name":"Product 1","owner":{"email":"[email protected]"},"price":11.5},{"name":"Product 2","owner":{"email":"[email protected]"},"price":12.5}]}
Example (QueryManyToManyViaJoinTable1) ¶
gql := `query {
products(limit: 2) {
name
customer {
email
}
owner {
email
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"customer":[{"email":"[email protected]"}],"name":"Product 1","owner":{"email":"[email protected]"}},{"customer":[{"email":"[email protected]"}],"name":"Product 2","owner":{"email":"[email protected]"}}]}
Example (QueryManyToManyViaJoinTable2) ¶
gql := `query {
users {
email
full_name
products {
name
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, DefaultLimit: 2})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":[{"email":"[email protected]","full_name":"User 1","products":[{"name":"Product 1"}]},{"email":"[email protected]","full_name":"User 2","products":[{"name":"Product 2"}]}]}
Example (QueryParentAndChildrenViaArrayColumn) ¶
gql := `
query {
products(limit: 2) {
name
price
categories {
id
name
}
}
categories {
name
products {
name
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, DefaultLimit: 2})
conf.Tables = []core.Table{{
Name: "products",
Columns: []core.Column{
{Name: "category_ids", ForeignKey: "categories.id", Array: true},
},
},
}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"categories":[{"name":"Category 1","products":[{"name":"Product 1"},{"name":"Product 2"}]},{"name":"Category 2","products":[{"name":"Product 1"},{"name":"Product 2"}]}],"products":[{"categories":[{"id":1,"name":"Category 1"},{"id":2,"name":"Category 2"}],"name":"Product 1","price":11.5},{"categories":[{"id":1,"name":"Category 1"},{"id":2,"name":"Category 2"}],"name":"Product 2","price":12.5}]}
Example (QueryParentsWithChildren) ¶
gql := `query {
users(order_by: { id: asc }, limit: 2) {
email
products {
name
price
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":[{"email":"[email protected]","products":[{"name":"Product 1","price":11.5}]},{"email":"[email protected]","products":[{"name":"Product 2","price":12.5}]}]}
Example (QueryWithAggregation) ¶
gql := `query {
products(where: { id: { lteq: 100 } }) {
count_id
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"count_id":100}]}
Example (QueryWithAggregationBlockedColumn) ¶
gql := `query {
products {
sum_price
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
err := conf.AddRoleTable("anon", "products", core.Query{
Columns: []string{"id", "name"},
})
if err != nil {
panic(err)
}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: db column blocked: price (role: 'anon')
Example (QueryWithAlternateFieldNames) ¶
gql := `query {
comments(limit: 2) {
id
commenter {
email
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"comments":[{"commenter":{"email":"[email protected]"},"id":1},{"commenter":{"email":"[email protected]"},"id":2}]}
Example (QueryWithCamelToSnakeCase) ¶
gql := `query {
hotProducts(where: { productID: { eq: 55 } }, order_by: { productID: desc }) {
countryCode
countProductID
products {
id
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, EnableCamelcase: true})
conf.Tables = []core.Table{
{
Name: "hot_products",
Columns: []core.Column{
{Name: "product_id", Type: "int", ForeignKey: "products.id"},
},
},
}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"hotProducts":[{"countProductID":1,"countryCode":"US","products":{"id":55}}]}
Example (QueryWithCursorPagination1) ¶
gql := `query {
products(
where: { id: { lesser_or_equals: 100 } }
first: 3
after: $cursor
order_by: { price: desc }) {
name
}
products_cursor
}`
vars := json.RawMessage(`{"cursor": null}`)
conf := newConfig(&core.Config{
DBType: dbType,
DisableAllowList: true,
SecretKey: "not_a_real_secret",
})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
return
}
type result struct {
Products json.RawMessage `json:"products"`
Cursor string `json:"products_cursor"`
}
var val result
if err := json.Unmarshal(res.Data, &val); err != nil {
fmt.Println(err)
return
}
if val.Cursor == "" {
fmt.Println("product_cursor value missing")
return
}
fmt.Println(string(val.Products))
Output: [{"name": "Product 100"}, {"name": "Product 99"}, {"name": "Product 98"}]
Example (QueryWithCursorPagination2) ¶
gql := `query {
products(
first: 5
after: $cursor
where: { id: { lte: 100 }}
order_by: { price: desc }) {
name
}
products_cursor
}`
conf := newConfig(&core.Config{
DBType: dbType,
DisableAllowList: true,
SecretKey: "not_a_real_secret",
})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
type result struct {
Products json.RawMessage `json:"products"`
Cursor string `json:"products_cursor"`
}
var val result
for i := 0; i < 5; i++ {
vars := json.RawMessage(
`{"cursor": "` + val.Cursor + `"}`)
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
return
}
if err := json.Unmarshal(res.Data, &val); err != nil {
fmt.Println(err)
return
}
fmt.Println(string(val.Products))
}
Output: [{"name": "Product 100"}, {"name": "Product 99"}, {"name": "Product 98"}, {"name": "Product 97"}, {"name": "Product 96"}] [{"name": "Product 95"}, {"name": "Product 94"}, {"name": "Product 93"}, {"name": "Product 92"}, {"name": "Product 91"}] [{"name": "Product 90"}, {"name": "Product 89"}, {"name": "Product 88"}, {"name": "Product 87"}, {"name": "Product 86"}] [{"name": "Product 85"}, {"name": "Product 84"}, {"name": "Product 83"}, {"name": "Product 82"}, {"name": "Product 81"}] [{"name": "Product 80"}, {"name": "Product 79"}, {"name": "Product 78"}, {"name": "Product 77"}, {"name": "Product 76"}]
Example (QueryWithDynamicOrderBy) ¶
gql := `
query getProducts {
products(order_by: $order, where: { id: { lt: 6 } }, limit: 5) {
id
price
}
}`
conf := newConfig(&core.Config{
DBType: dbType,
DisableAllowList: true,
Tables: []core.Table{{
Name: "products",
OrderBy: map[string][]string{
"price_and_id": {"price desc", "id asc"},
"just_id": {"id asc"},
},
}},
})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
vars1 := json.RawMessage(`{ "order": "price_and_id" }`)
res1, err1 := gj.GraphQL(context.Background(), gql, vars1, nil)
if err != nil {
fmt.Println(err1)
} else {
printJSON(res1.Data)
}
vars2 := json.RawMessage(`{ "order": "just_id" }`)
res2, err2 := gj.GraphQL(context.Background(), gql, vars2, nil)
if err != nil {
fmt.Println(err2)
} else {
printJSON(res2.Data)
}
Output: {"products":[{"id":5,"price":15.5},{"id":4,"price":14.5},{"id":3,"price":13.5},{"id":2,"price":12.5},{"id":1,"price":11.5}]} {"products":[{"id":1,"price":11.5},{"id":2,"price":12.5},{"id":3,"price":13.5},{"id":4,"price":14.5},{"id":5,"price":15.5}]}
Example (QueryWithFragments1) ¶
gql := `
fragment userFields1 on user {
id
email
}
query {
users {
...userFields2
stripe_id
...userFields1
}
}
fragment userFields2 on user {
full_name
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, DefaultLimit: 2})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":[{"email":"[email protected]","full_name":"User 1","id":1,"stripe_id":"payment_id_1001"},{"email":"[email protected]","full_name":"User 2","id":2,"stripe_id":"payment_id_1002"}]}
Example (QueryWithFragments2) ¶
gql := `
query {
users {
...userFields2
stripe_id
...userFields1
}
}
fragment userFields1 on user {
id
email
}
fragment userFields2 on user {
full_name
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, DefaultLimit: 2})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":[{"email":"[email protected]","full_name":"User 1","id":1,"stripe_id":"payment_id_1001"},{"email":"[email protected]","full_name":"User 2","id":2,"stripe_id":"payment_id_1002"}]}
Example (QueryWithFragments3) ¶
gql := `
fragment userFields1 on user {
id
email
}
fragment userFields2 on user {
full_name
...userFields1
}
query {
users {
...userFields2
stripe_id
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, DefaultLimit: 2})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":[{"email":"[email protected]","full_name":"User 1","id":1,"stripe_id":"payment_id_1001"},{"email":"[email protected]","full_name":"User 2","id":2,"stripe_id":"payment_id_1002"}]}
Example (QueryWithFunctionFields) ¶
gql := `
query {
products(id: 51) {
id
name
is_hot_product(id: id)
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":{"id":51,"is_hot_product":true,"name":"Product 51"}}
Example (QueryWithFunctionFieldsArgList) ¶
gql := `
query {
products(id: 51) {
id
name
is_hot_product(args: [51])
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":{"id":51,"is_hot_product":true,"name":"Product 51"}}
Example (QueryWithFunctionReturingTables) ¶
gql := `query {
get_oldest5_products(limit: 3) {
id
name
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"get_oldest5_products":[{"id":1,"name":"Product 1"},{"id":2,"name":"Product 2"},{"id":3,"name":"Product 3"}]}
Example (QueryWithFunctionReturingTablesWithArgs) ¶
gql := `query {
get_oldest_users(limit: 2, args: [4, $tag]) {
tag_name
id
full_name
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
vars := json.RawMessage(`{ "tag": "boo" }`)
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"get_oldest_users":[{"full_name":"User 1","id":1,"tag_name":"boo"},{"full_name":"User 2","id":2,"tag_name":"boo"}]}
Example (QueryWithFunctionReturingTablesWithNamedArgs) ¶
gql := `query {
get_oldest_users(limit: 2, user_count: 4, tag: $tag) {
tag_name
id
full_name
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
vars := json.RawMessage(`{ "tag": "boo" }`)
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"get_oldest_users":[{"full_name":"User 1","id":1,"tag_name":"boo"},{"full_name":"User 2","id":2,"tag_name":"boo"}]}
Example (QueryWithFunctionReturingUserDefinedTypes) ¶
gql := `query {
get_product(limit: 2, args: [1]) {
id
name
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"get_product":[{"id":1,"name":"Product 1"},{"id":2,"name":"Product 2"}]}
Example (QueryWithFunctionsBlocked) ¶
gql := `query {
products {
sum_price
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
err := conf.AddRoleTable("anon", "products", core.Query{
DisableFunctions: true,
})
if err != nil {
panic(err)
}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: all db functions blocked: sum (role: 'anon')
Example (QueryWithFunctionsWithWhere) ¶
gql := `query {
products(where: { id: { lesser_or_equals: 100 } }) {
max_price
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"max_price":110.5}]}
Example (QueryWithJsonColumn) ¶
gql := `query {
users(id: 1) {
id
category_counts {
count
category {
name
}
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
conf.Tables = []core.Table{
{
Name: "category_counts",
Table: "users",
Type: "json",
Columns: []core.Column{
{Name: "category_id", Type: "int", ForeignKey: "categories.id"},
{Name: "count", Type: "int"},
},
},
}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":{"category_counts":[{"category":{"name":"Category 1"},"count":400},{"category":{"name":"Category 2"},"count":600}],"id":1}}
Example (QueryWithLimitOffsetOrderByDistinctAndWhere) ¶
gql := `query {
products(
# returns only 5 items
limit: 5,
# starts from item 10, commented out for now
# offset: 10,
# orders the response items by highest price
order_by: { price: desc },
# no duplicate prices returned
distinct: [ price ]
# only items with an id >= 50 and < 100 are returned
where: { id: { and: { greater_or_equals: 50, lt: 100 } } }) {
id
name
price
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":99,"name":"Product 99","price":109.5},{"id":98,"name":"Product 98","price":108.5},{"id":97,"name":"Product 97","price":107.5},{"id":96,"name":"Product 96","price":106.5},{"id":95,"name":"Product 95","price":105.5}]}
Example (QueryWithMultipleTopLevelTables) ¶
gql := `query {
products(id: $id) {
id
name
customer {
email
}
}
users(id: $id) {
id
email
}
purchases(id: $id) {
id
}
}`
vars := json.RawMessage(`{ "id": 1 }`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":{"customer":[{"email":"[email protected]"}],"id":1,"name":"Product 1"},"purchases":{"id":1},"users":{"email":"[email protected]","id":1}}
Example (QueryWithNestedOrderBy) ¶
gql := `
query getProducts {
products(order_by: { users: { email: desc }, id: desc}, where: { id: { lt: 6 } }, limit: 5) {
id
price
}
}`
conf := newConfig(&core.Config{
DBType: dbType,
DisableAllowList: true,
})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":5,"price":15.5},{"id":4,"price":14.5},{"id":3,"price":13.5},{"id":2,"price":12.5},{"id":1,"price":11.5}]}
Example (QueryWithOrderByList) ¶
gql := `
query getProducts {
products(order_by: { id: [$list, "asc"] }, where: { id: { in: $list } }, limit: 5) {
id
price
}
}`
conf := newConfig(&core.Config{
DBType: dbType,
DisableAllowList: true,
})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
vars := json.RawMessage(`{ "list": [3, 2, 1, 5] }`)
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":3,"price":13.5},{"id":2,"price":12.5},{"id":1,"price":11.5},{"id":5,"price":15.5}]}
Example (QueryWithRecursiveRelationship1) ¶
gql := `query {
reply : comments(id: $id) {
id
comments(
where: { id: { lt: 50 } },
limit: 5,
find: "parents") {
id
}
}
}`
vars := json.RawMessage(`{"id": 50 }`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"reply":{"comments":[{"id":49},{"id":48},{"id":47},{"id":46},{"id":45}],"id":50}}
Example (QueryWithRecursiveRelationship2) ¶
gql := `query {
comments(id: 95) {
id
replies: comments(find: "children") {
id
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"comments":{"id":95,"replies":[{"id":96},{"id":97},{"id":98},{"id":99},{"id":100}]}}
Example (QueryWithRecursiveRelationshipAndAggregations) ¶
gql := `query {
comments(id: 95) {
id
replies: comments(find: "children") {
count_id
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"comments":{"id":95,"replies":[{"count_id":5}]}}
Example (QueryWithRemoteAPIJoin) ¶
gql := `query {
users {
email
payments {
desc
}
}
}`
// fake remote api service
go func() {
http.HandleFunc("/payments/", func(w http.ResponseWriter, r *http.Request) {
id := r.URL.Path[10:]
fmt.Fprintf(w, `{"data":[{"desc":"Payment 1 for %s"},{"desc": "Payment 2 for %s"}]}`,
id, id)
})
log.Fatal(http.ListenAndServe("localhost:12345", nil)) //nolint:gosec
}()
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, DefaultLimit: 2})
conf.Resolvers = []core.ResolverConfig{{
Name: "payments",
Type: "remote_api",
Table: "users",
Column: "stripe_id",
StripPath: "data",
Props: core.ResolverProps{"url": "http://localhost:12345/payments/$id"},
}}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":[{"email":"[email protected]","payments":[{"desc":"Payment 1 for payment_id_1001"},{"desc":"Payment 2 for payment_id_1001"}]},{"email":"[email protected]","payments":[{"desc":"Payment 1 for payment_id_1002"},{"desc":"Payment 2 for payment_id_1002"}]}]}
Example (QueryWithScriptDirective) ¶
gql := `query @script(name: "test.js") {
usersByID(id: $id) {
id
email
}
}`
script := `
function request(vars) {
return { id: 2 };
}
function response(json) {
json.usersByID.email = "[email protected]";
return json;
}
`
dir, err := os.MkdirTemp("", "test")
if err != nil {
panic(err)
}
defer os.RemoveAll(dir)
err = os.WriteFile(path.Join(dir, "test.js"), []byte(script), 0600)
if err != nil {
panic(err)
}
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, ScriptPath: dir})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"usersByID":{"email":"[email protected]","id":2}}
Example (QueryWithScriptDirectiveUsingGraphQL) ¶
gql := `query @script(name: "test.js") {
usersByID(id: 2) {
id
email
}
}`
script := `
function response(json) {
let val = graphql('query { users(id: 1) { id email } }')
json.usersByID.email = val.users.email
return json;
}
`
dir, err := os.MkdirTemp("", "test")
if err != nil {
panic(err)
}
defer os.RemoveAll(dir)
err = os.WriteFile(path.Join(dir, "test.js"), []byte(script), 0600)
if err != nil {
panic(err)
}
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, ScriptPath: dir})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"usersByID":{"email":"[email protected]","id":2}}
Example (QueryWithScriptDirectiveUsingHttp) ¶
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, `{ "hello": "world" }`)
}))
defer ts.Close()
gql := `query @script(name: "test.js") {
usersByID(id: 2) {
id
email
}
}`
script := `
function response(json) {
let val = http.get("` + ts.URL + `")
return JSON.parse(val);
}
`
dir, err := os.MkdirTemp("", "test")
if err != nil {
panic(err)
}
defer os.RemoveAll(dir)
err = os.WriteFile(path.Join(dir, "test.js"), []byte(script), 0600)
if err != nil {
panic(err)
}
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, ScriptPath: dir})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"hello":"world"}
Example (QueryWithSkipAndIncludeDirectives) ¶
gql := `
query {
products(limit: 2) @include(if: $test) {
id
name
}
users(limit: 3) @skip(if: $test) {
id
}
}`
vars := json.RawMessage(`{ "test": true }`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":1,"name":"Product 1"},{"id":2,"name":"Product 2"}],"users":[]}
Example (QueryWithSkipAndIncludeFieldDirectives) ¶
gql := `
query {
products(limit: 2) {
id @include(if: $test)
name
}
users(limit: 3) {
id @skip(if: $test)
}
}`
vars := json.RawMessage(`{ "test": true }`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":1,"name":"Product 1"},{"id":2,"name":"Product 2"}],"users":[{"id":null},{"id":null},{"id":null}]}
Example (QueryWithSkippingAuthRequiredSelectors) ¶
gql := `query {
products(limit: 2) {
id
name
owner(where: { id: { eq: $user_id } }) {
id
email
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":1,"name":"Product 1","owner":null},{"id":2,"name":"Product 2","owner":null}]}
Example (QueryWithSyntheticTables) ¶
gql := `query {
me @object {
email
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
conf.Tables = []core.Table{{Name: "me", Table: "users"}}
err := conf.AddRoleTable("user", "me", core.Query{
Filters: []string{`{ id: $user_id }`},
Limit: 1,
})
if err != nil {
panic(err)
}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 1)
res, err := gj.GraphQL(ctx, gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"me":{"email":"[email protected]"}}
Example (QueryWithTypename) ¶
gql := `query getUser {
__typename
users(id: 1) {
id
email
__typename
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, json.RawMessage(`{"id":2}`), nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"__typename":"getUser","users":{"__typename":"users","email":"[email protected]","id":1}}
Example (QueryWithUnionForPolymorphicRelationships) ¶
gql := `
fragment userFields on user {
email
}
fragment productFields on product {
name
}
query {
notifications {
id
verb
subject {
...on users {
...userFields
}
...on products {
...productFields
}
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, DefaultLimit: 2})
conf.Tables = []core.Table{{
Name: "subject",
Type: "polymorphic",
Columns: []core.Column{{Name: "subject_id", ForeignKey: "subject_type.id"}},
}}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"notifications":[{"id":1,"subject":{"email":"[email protected]"},"verb":"Joined"},{"id":2,"subject":{"name":"Product 2"},"verb":"Bought"}]}
Example (QueryWithUser) ¶
gql := `
query {
products(where: { owner_id: { eq: $user_id } }) {
id
owner {
id
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 31)
res, err := gj.GraphQL(ctx, gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":31,"owner":{"id":31}}]}
Example (QueryWithVariableLimit) ¶
gql := `query {
products(limit: $limit) {
id
}
}`
vars := json.RawMessage(`{
"limit": 10
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":1},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10}]}
Example (QueryWithVariables) ¶
gql := `query {
products(id: $product_id, where: { price: { gt: $product_price } }) {
id
name
}
}`
vars := json.RawMessage(`{ "product_id": 70 }`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
conf.Vars = map[string]string{"product_price": "50"}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":{"id":70,"name":"Product 70"}}
Example (QueryWithView) ¶
gql := `query {
hot_products(limit: 3) {
product {
id
name
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
conf.Tables = []core.Table{
{
Name: "hot_products",
Columns: []core.Column{
{Name: "product_id", Type: "int", ForeignKey: "products.id"},
},
},
}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"hot_products":[{"product":{"id":51,"name":"Product 51"}},{"product":{"id":52,"name":"Product 52"}},{"product":{"id":53,"name":"Product 53"}}]}
Example (QueryWithWhere1) ¶
gql := `query {
products(where: {
id: [3, 34],
or: {
name: { iregex: $name },
description: { iregex: $name }
}
}) {
id
}
}`
vars := json.RawMessage(`{
"name": "Product 3"
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":3},{"id":34}]}
Example (QueryWithWhereGreaterThanOrLesserThan) ¶
gql := `query {
products(
limit: 3
where: {
or: {
price: { gt: 20 },
price: { lt: 22 }
} }
) {
id
name
price
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":1,"name":"Product 1","price":11.5},{"id":2,"name":"Product 2","price":12.5},{"id":3,"name":"Product 3","price":13.5}]}
Example (QueryWithWhereHasAnyKey) ¶
gql := `query {
products(
where: { metadata: { has_key_any: ["foo", "bar"] } }
limit: 3
) {
id
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":1},{"id":2},{"id":3}]}
Example (QueryWithWhereIn) ¶
gql := `query {
products(where: { id: { in: $list } }) {
id
}
}`
vars := json.RawMessage(`{
"list": [1,2,3]
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":1},{"id":2},{"id":3}]}
Example (QueryWithWhereNotIsNullAndGreaterThan) ¶
gql := `query {
products(
where: {
and: [
{ not: { id: { is_null: true } } },
{ price: { gt: 10 } },
]
}
limit: 3) {
id
name
price
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":1,"name":"Product 1","price":11.5},{"id":2,"name":"Product 2","price":12.5},{"id":3,"name":"Product 3","price":13.5}]}
Example (QueryWithWhereOnRelatedTable) ¶
gql := `query {
products(where: { owner: { id: { or: [ { eq: $user_id }, { eq: 3 } ] } } }, limit: 2) {
id
owner {
id
email
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 2)
res, err := gj.GraphQL(ctx, gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":2,"owner":{"email":"[email protected]","id":2}},{"id":3,"owner":{"email":"[email protected]","id":3}}]}
Example (SetArrayColumnToEmpty) ¶
gql := `mutation {
products(where: { id: 100 }, update: { tags: [] }) {
id
tags
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":100,"tags":[]}]}
Example (SetArrayColumnToValue) ¶
gql := `mutation {
products(where: { id: 100 }, update: { tags: ["super", "great", "wow"] }) {
id
tags
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, nil, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":[{"id":100,"tags":["super","great","wow"]}]}
Example (Subscription) ¶
gql := `subscription test {
users(id: $id) {
id
email
phone
}
}`
vars := json.RawMessage(`{ "id": 3 }`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true, SubsPollDuration: 1})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
m, err := gj.Subscribe(context.Background(), gql, vars, nil)
if err != nil {
fmt.Println(err)
return
}
for i := 0; i < 10; i++ {
msg := <-m.Result
printJSON(msg.Data)
// update user phone in database to trigger subscription
q := fmt.Sprintf(`UPDATE users SET phone = '650-447-000%d' WHERE id = 3`, i)
if _, err := db.Exec(q); err != nil {
panic(err)
}
}
Output: {"users":{"email":"[email protected]","id":3,"phone":null}} {"users":{"email":"[email protected]","id":3,"phone":"650-447-0000"}} {"users":{"email":"[email protected]","id":3,"phone":"650-447-0001"}} {"users":{"email":"[email protected]","id":3,"phone":"650-447-0002"}} {"users":{"email":"[email protected]","id":3,"phone":"650-447-0003"}} {"users":{"email":"[email protected]","id":3,"phone":"650-447-0004"}} {"users":{"email":"[email protected]","id":3,"phone":"650-447-0005"}} {"users":{"email":"[email protected]","id":3,"phone":"650-447-0006"}} {"users":{"email":"[email protected]","id":3,"phone":"650-447-0007"}} {"users":{"email":"[email protected]","id":3,"phone":"650-447-0008"}}
Example (SubscriptionWithCursor) ¶
// func TestSubCursor(t *testing.T) {
// query to fetch existing chat messages
// gql1 := `query {
// chats(first: 3, after: $cursor) {
// id
// body
// }
// chats_cursor
// }`
// query to subscribe to new chat messages
gql2 := `subscription {
chats(first: 1, after: $cursor) {
id
body
}
}`
conf := newConfig(&core.Config{
DBType: dbType,
DisableAllowList: true,
SubsPollDuration: 1,
SecretKey: "not_a_real_secret",
})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
// struct to hold the cursor value from fetching the existing
// chat messages
// res := struct {
// Cursor string `json:"chats_cursor"`
// }{}
// execute query for existing chat messages
// m1, err := gj.GraphQL(context.Background(), gql1, nil, nil)
// if err != nil {
// fmt.Println(err)
// return
// }
// extract out the cursor `chats_cursor` to use in the subscription
// if err := json.Unmarshal(m1.Data, &res); err != nil {
// fmt.Println(err)
// return
// }
// replace cursor value to make test work since it's encrypted
// v1 := cursorRegex.ReplaceAllString(string(m1.Data), "cursor_was_here")
// fmt.Println(v1)
// create variables with the previously extracted cursor value to
// pass to the new chat messages subscription
// vars := json.RawMessage(`{ "cursor": "` + res.Cursor + `" }`)
vars := json.RawMessage(`{ "cursor": null }`)
// subscribe to new chat messages using the cursor
m2, err := gj.Subscribe(context.Background(), gql2, vars, nil)
if err != nil {
fmt.Println(err)
return
}
go func() {
for i := 6; i < 20; i++ {
// insert a new chat message
q := fmt.Sprintf(`INSERT INTO chats (id, body) VALUES (%d, 'New chat message %d')`, i, i)
if _, err := db.Exec(q); err != nil {
panic(err)
}
time.Sleep(3 * time.Second)
}
}()
for i := 0; i < 19; i++ {
msg := <-m2.Result
// replace cursor value to make test work since it's encrypted
v2 := cursorRegex.ReplaceAllString(string(msg.Data), `cursor":"cursor_was_here`)
printJSON([]byte(v2))
}
Output: {"chats":[{"body":"This is chat message number 1","id":1}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"This is chat message number 2","id":2}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"This is chat message number 3","id":3}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"This is chat message number 4","id":4}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"This is chat message number 5","id":5}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 6","id":6}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 7","id":7}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 8","id":8}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 9","id":9}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 10","id":10}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 11","id":11}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 12","id":12}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 13","id":13}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 14","id":14}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 15","id":15}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 16","id":16}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 17","id":17}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 18","id":18}],"chats_cursor":"cursor_was_here"} {"chats":[{"body":"New chat message 19","id":19}],"chats_cursor":"cursor_was_here"}
Example (Update) ¶
gql := `mutation {
products(id: $id, update: $data) {
id
name
}
}`
vars := json.RawMessage(`{
"id": 100,
"data": {
"name": "Updated Product 100",
"description": "Description for updated product 100"
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"products":{"id":100,"name":"Updated Product 100"}}
Example (UpdateMultipleRelatedTables1) ¶
gql := `mutation {
purchases(id: $id, update: $data) {
quantity
customer {
full_name
}
product {
description
}
}
}`
vars := json.RawMessage(`{
"id": 100,
"data": {
"quantity": 6,
"customer": {
"full_name": "Updated user related to purchase 100"
},
"product": {
"description": "Updated product related to purchase 100"
}
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"purchases":{"customer":{"full_name":"Updated user related to purchase 100"},"product":{"description":"Updated product related to purchase 100"},"quantity":6}}
Example (UpdateTableAndConnectToRelatedTables) ¶
gql := `mutation {
users(id: $id, update: $data) {
full_name
products {
id
}
}
}`
vars := json.RawMessage(`{
"id": 100,
"data": {
"full_name": "Updated user 100",
"products": {
"connect": { "id": 99 },
"disconnect": { "id": 100 }
}
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":{"full_name":"Updated user 100","products":[{"id":99}]}}
Example (UpdateTableAndRelatedTable) ¶
gql := `mutation {
users(id: $id, update: $data) {
full_name
products {
id
}
}
}`
vars := json.RawMessage(`{
"id": 90,
"data": {
"full_name": "Updated user 90",
"products": {
"where": { "id": { "gt": 1 } },
"name": "Updated Product 90"
}
}
}`)
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
panic(err)
}
ctx := context.WithValue(context.Background(), core.UserIDKey, 3)
res, err := gj.GraphQL(ctx, gql, vars, nil)
if err != nil {
fmt.Println(err)
} else {
printJSON(res.Data)
}
Output: {"users":{"full_name":"Updated user 90","products":[{"id":90}]}}
Example (VeryComplexQueryWithArrayColumns) ¶
TODO: Fix: Does not work in MYSQL
gql := `query {
products(
# returns only 1 items
limit: 1,
# 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
name
price
owner {
full_name
picture : avatar
email
category_counts(limit: 2) {
count
category {
name
}
}
}
category(limit: 2) {
id
name
}
}
}`
conf := newConfig(&core.Config{DBType: dbType, DisableAllowList: true})
conf.Tables = []core.Table{
{
Name: "category_counts",
Table: "users",
Type: "json",
Columns: []core.Column{
{Name: "category_id", Type: "int", ForeignKey: "categories.id"},
{Name: "count", Type: "int"},
},
},
{
Name: "products",
Columns: []core.Column{{Name: "category_ids", ForeignKey: "categories.id"}},
},
}
gj, err := core.NewGraphJin(conf, db)
if err != nil {
fmt.Println(err)
return
}
res, err := gj.GraphQL(context.Background(), gql, nil, nil)
if err != nil {
fmt.Println(err)
return
}
printJSON(res.Data)
Output: {"products":[{"category":[{"id":1,"name":"Category 1"},{"id":2,"name":"Category 2"}],"id":27,"name":"Product 27","owner":{"category_counts":[{"category":{"name":"Category 1"},"count":400},{"category":{"name":"Category 2"},"count":600}],"email":"[email protected]","full_name":"User 27","picture":null},"price":37.5}]}
Index ¶
- Constants
- Variables
- func GetConfigName() string
- type Column
- type Config
- type Delete
- type Error
- type GraphJin
- func (g *GraphJin) GraphQL(c context.Context, query string, vars json.RawMessage, rc *ReqConfig) (*Result, error)
- func (g *GraphJin) GraphQLByName(c context.Context, operation OpType, name string, vars json.RawMessage, ...) (*Result, error)
- func (g *GraphJin) IsProd() bool
- func (g *GraphJin) Reload() error
- func (g *GraphJin) Subscribe(c context.Context, query string, vars json.RawMessage, rc *ReqConfig) (*Member, error)
- type Header
- type Insert
- type Member
- type Namespace
- type OpType
- type Option
- type Query
- type ReqConfig
- type Resolver
- type ResolverConfig
- type ResolverProps
- type ResolverReq
- type Result
- type Role
- type RoleTable
- type Table
- type Update
- type Upsert
Examples ¶
- Package (Insert)
- Package (InsertBulk)
- Package (InsertInline)
- Package (InsertInlineBulk)
- Package (InsertInlineWithValidation)
- Package (InsertIntoMultipleRelatedTables)
- Package (InsertIntoRecursiveRelationship)
- Package (InsertIntoRecursiveRelationshipAndConnectTable1)
- Package (InsertIntoRecursiveRelationshipAndConnectTable2)
- Package (InsertIntoTableAndConnectToRelatedTableWithArrayColumn)
- Package (InsertIntoTableAndConnectToRelatedTables)
- Package (InsertIntoTableAndRelatedTable1)
- Package (InsertIntoTableAndRelatedTable2)
- Package (InsertIntoTableBulkInsertIntoRelatedTable)
- Package (InsertWithCamelToSnakeCase)
- Package (InsertWithPresets)
- Package (Query)
- Package (QueryBlockWithRoles)
- Package (QueryByID)
- Package (QueryBySearch)
- Package (QueryChildrenWithParent)
- Package (QueryManyToManyViaJoinTable1)
- Package (QueryManyToManyViaJoinTable2)
- Package (QueryParentAndChildrenViaArrayColumn)
- Package (QueryParentsWithChildren)
- Package (QueryWithAggregation)
- Package (QueryWithAggregationBlockedColumn)
- Package (QueryWithAlternateFieldNames)
- Package (QueryWithCamelToSnakeCase)
- Package (QueryWithCursorPagination1)
- Package (QueryWithCursorPagination2)
- Package (QueryWithDynamicOrderBy)
- Package (QueryWithFragments1)
- Package (QueryWithFragments2)
- Package (QueryWithFragments3)
- Package (QueryWithFunctionFields)
- Package (QueryWithFunctionFieldsArgList)
- Package (QueryWithFunctionReturingTables)
- Package (QueryWithFunctionReturingTablesWithArgs)
- Package (QueryWithFunctionReturingTablesWithNamedArgs)
- Package (QueryWithFunctionReturingUserDefinedTypes)
- Package (QueryWithFunctionsBlocked)
- Package (QueryWithFunctionsWithWhere)
- Package (QueryWithJsonColumn)
- Package (QueryWithLimitOffsetOrderByDistinctAndWhere)
- Package (QueryWithMultipleTopLevelTables)
- Package (QueryWithNestedOrderBy)
- Package (QueryWithOrderByList)
- Package (QueryWithRecursiveRelationship1)
- Package (QueryWithRecursiveRelationship2)
- Package (QueryWithRecursiveRelationshipAndAggregations)
- Package (QueryWithRemoteAPIJoin)
- Package (QueryWithScriptDirective)
- Package (QueryWithScriptDirectiveUsingGraphQL)
- Package (QueryWithScriptDirectiveUsingHttp)
- Package (QueryWithSkipAndIncludeDirectives)
- Package (QueryWithSkipAndIncludeFieldDirectives)
- Package (QueryWithSkippingAuthRequiredSelectors)
- Package (QueryWithSyntheticTables)
- Package (QueryWithTypename)
- Package (QueryWithUnionForPolymorphicRelationships)
- Package (QueryWithUser)
- Package (QueryWithVariableLimit)
- Package (QueryWithVariables)
- Package (QueryWithView)
- Package (QueryWithWhere1)
- Package (QueryWithWhereGreaterThanOrLesserThan)
- Package (QueryWithWhereHasAnyKey)
- Package (QueryWithWhereIn)
- Package (QueryWithWhereNotIsNullAndGreaterThan)
- Package (QueryWithWhereOnRelatedTable)
- Package (SetArrayColumnToEmpty)
- Package (SetArrayColumnToValue)
- Package (Subscription)
- Package (SubscriptionWithCursor)
- Package (Update)
- Package (UpdateMultipleRelatedTables1)
- Package (UpdateTableAndConnectToRelatedTables)
- Package (UpdateTableAndRelatedTable)
- Package (VeryComplexQueryWithArrayColumns)
Constants ¶
const ( // Name of the authentication provider. Eg. google, github, etc UserIDProviderKey contextkey = iota // The raw user id (jwt sub) value UserIDRawKey // User ID value for authenticated users UserIDKey // User role if pre-defined UserRoleKey )
Constants to set values on the context passed to the NewGraphJin function
Variables ¶
var (
ErrNotFound = errors.New("not found in prepared statements")
)
Functions ¶
func GetConfigName ¶ added in v0.17.7
func GetConfigName() string
Types ¶
type Column ¶
type Column struct {
Name string
Type string `jsonschema:"example=integer,example=text"`
Primary bool
Array bool
ForeignKey string `mapstructure:"related_to" jsonschema:"title=Related To,example=other_table.id_column,example=users.id"`
}
Configuration for a database table column
type Config ¶
type Config struct {
// Is used to encrypt opaque values such as the cursor. Auto-generated when not set
SecretKey string `mapstructure:"secret_key" jsonschema:"title=Secret Key"`
// When set to true it disables the allow list workflow and all queries are
// always compiled even in production (Warning possible security concern)
DisableAllowList bool `mapstructure:"disable_allow_list" jsonschema:"title=Disable Allow List,default=false"`
// The default path to find all configuration files and scripts under
ConfigPath string `mapstructure:"config_path" jsonschema:"title=Config Path,default=./config"`
// The default path to find all scripts under
ScriptPath string `mapstructure:"script_path" jsonschema:"title=Config Path,default=./config/scripts"`
// Forces the database session variable 'user.id' to be set to the user id
SetUserID bool `mapstructure:"set_user_id" jsonschema:"title=Set User ID,default=false"`
// This ensures that for anonymous users (role 'anon') all tables are blocked
// from queries and mutations. To open access to tables for anonymous users
// they have to be added to the 'anon' role config
DefaultBlock bool `mapstructure:"default_block" jsonschema:"title=Block tables for anonymous users,default=true"`
// This is a list of variables that can be leveraged in your queries.
// (eg. variable admin_id will be $admin_id in the query)
Vars map[string]string `mapstructure:"variables" jsonschema:"title=Variables"`
// This is a list of variables that map to http header values
HeaderVars map[string]string `mapstructure:"header_variables" jsonschema:"title=Header Variables"`
// A list of tables and columns that should disallowed in any and all queries
Blocklist []string `jsonschema:"title=Block List"`
// The configs for custom resolvers. For example the `remote_api`
// resolver would join json from a remote API into your query response
Resolvers []ResolverConfig `jsonschema:"-"`
// All table specific configuration such as aliased tables and relationships
// between tables
Tables []Table `jsonschema:"title=Tables"`
// An SQL query if set enables attribute based access control. This query is
// used to fetch the user attribute that then dynamically define the users role
RolesQuery string `mapstructure:"roles_query" jsonschema:"title=Roles Query"`
// Roles contains the configuration for all the roles you want to support 'user' and
// 'anon' are two default roles. The 'user' role is used when a user ID is available
// and 'anon' when it's not. Use the 'Roles Query' config to add more custom roles
Roles []Role
// Inflections is to add additionally singular to plural mappings
// to the engine (eg. sheep: sheep)
Inflections []string `mapstructure:"inflections" jsonschema:"-"`
// Disable inflections. Inflections are deprecated and will be
// removed in next major version
EnableInflection bool `mapstructure:"enable_inflection" jsonschema:"-"`
// Customize singular suffix. Default value is "ByID"
SingularSuffix string `mapstructure:"singular_suffix" jsonschema:"title=Singular Suffix,default=ById"`
// Database type name Defaults to 'postgres' (options: mysql, postgres)
DBType string `mapstructure:"db_type" jsonschema:"title=Database Type,enum=postgres,enum=mysql"`
// Log warnings and other debug information
Debug bool `jsonschema:"title=Debug,default=false"`
// Database polling duration (in seconds) used by subscriptions to
// query for updates.
SubsPollDuration time.Duration `mapstructure:"subs_poll_duration" jsonschema:"title=Subscription Polling Duration,default=5s"`
// The default max limit (number of rows) when a limit is not defined in
// the query or the table role config.
DefaultLimit int `mapstructure:"default_limit" jsonschema:"title=Default Row Limit,default=20"`
// Disable all aggregation functions like count, sum, etc
DisableAgg bool `mapstructure:"disable_agg_functions" jsonschema:"title=Disable Aggregations,default=false"`
// Disable all functions like count, length, etc
DisableFuncs bool `mapstructure:"disable_functions" jsonschema:"title=Disable Functions,default=false"`
// Enable automatic coversion of camel case in GraphQL to snake case in SQL
EnableCamelcase bool `mapstructure:"enable_camelcase" jsonschema:"title=Enable Camel Case,default=false"`
// Enable production mode. This defaults to true if GO_ENV is set to
// "production". When true the allow list is enforced
Production bool `jsonschema:"title=Production Mode,default=false"`
// Duration for polling the database to detect schema changes
DBSchemaPollDuration time.Duration `mapstructure:"db_schema_poll_duration" jsonschema:"title=Schema Change Detection Polling Duration,default=10s"`
// contains filtered or unexported fields
}
Configuration for the GraphJin compiler core
func ReadInConfig ¶
ReadInConfig reads in the config file for the environment specified in the GO_ENV environment variable. This is the best way to create a new GraphJin config.
func ReadInConfigFS ¶ added in v0.17.0
ReadInConfigFS is the same as ReadInConfig but it also takes a filesytem as an argument
func (*Config) AddRoleTable ¶
AddRoleTable function is a helper function to make it easy to add per-table row-level config
func (*Config) RemoveRoleTable ¶ added in v0.16.7
func (*Config) SetResolver ¶ added in v0.15.56
type GraphJin ¶
func NewGraphJin ¶
NewGraphJin creates the GraphJin struct, this involves querying the database to learn its schemas and relationships
func (*GraphJin) GraphQL ¶
func (g *GraphJin) GraphQL( c context.Context, query string, vars json.RawMessage, rc *ReqConfig) (*Result, error)
GraphQL function is called on the GraphJin struct to convert the provided GraphQL query into an SQL query and execute it on the database. In production mode prepared statements are directly used and no query compiling takes places.
In developer mode all names queries are saved into a file `allow.list` and in production mode only queries from this file can be run.
func (*GraphJin) GraphQLByName ¶ added in v0.20.4
func (*GraphJin) IsProd ¶ added in v0.16.28
IsProd return true for production mode or false for development mode
type Member ¶
type Member struct {
Result chan *Result
// contains filtered or unexported fields
}
func (*Member) Unsubscribe ¶
func (m *Member) Unsubscribe()
type Option ¶ added in v0.17.0
type Option func(*graphjin) error
func OptionSetFS ¶ added in v0.17.0
func OptionSetNamespace ¶ added in v0.17.21
type Query ¶
type Query struct {
Limit int
Filters []string
Columns []string
DisableFunctions bool `mapstructure:"disable_functions"`
Block bool
}
Table configuration for querying a table with a role
type ReqConfig ¶
type ReqConfig struct {
// Namespace is used to namespace requests within a single instance of GraphJin. For example queries with the same name
// can exist in allow list in seperate namespaces.
Namespace Namespace
// APQKey is set when using GraphJin with automatic persisted queries
APQKey string
// Pass additional variables complex variables such as functions that return string values.
Vars map[string]interface{}
}
ReqConfig is used to pass request specific config values to the GraphQLEx and SubscribeEx functions. Dynamic variables can be set here.
type Resolver ¶ added in v0.15.56
type Resolver interface {
Resolve(context.Context, ResolverReq) ([]byte, error)
}
Resolver interface is used to create custom resolvers Custom resolvers must return a JSON value to be merged into the response JSON.
Example Redis Resolver:
type Redis struct {
Addr string
client redis.Client
}
func newRedis(v map[string]interface{}) (*Redis, error) {
re := &Redis{}
if err := mapstructure.Decode(v, re); err != nil {
return nil, err
}
re.client := redis.NewClient(&redis.Options{
Addr: re.Addr,
Password: "", // no password set
DB: 0, // use default DB
})
return re, nil
}
func (r *remoteAPI) Resolve(req ResolverReq) ([]byte, error) {
val, err := rdb.Get(ctx, req.ID).Result()
if err != nil {
return err
}
return val, nil
}
func main() {
conf := core.Config{
Resolvers: []Resolver{
Name: "cached_profile",
Type: "redis",
Table: "users",
Column: "id",
Props: []ResolverProps{
"addr": "localhost:6379",
},
},
}
gj.conf.SetResolver("redis", func(v ResolverProps) (Resolver, error) {
return newRedis(v)
})
gj, err := core.NewGraphJin(conf, db)
if err != nil {
log.Fatal(err)
}
}
type ResolverConfig ¶ added in v0.15.56
type ResolverConfig struct {
Name string
Type string
Schema string
Table string
Column string
StripPath string `mapstructure:"strip_path"`
Props ResolverProps `mapstructure:",remain"`
}
ResolverConfig struct defines a custom resolver
type ResolverProps ¶ added in v0.15.56
type ResolverProps map[string]interface{}
ResolverProps is a map of properties from the resolver config to be passed to the customer resolver's builder (new) function
type ResolverReq ¶ added in v0.15.56
type Result ¶
type Result struct {
Errors []Error `json:"errors,omitempty"`
Vars json.RawMessage `json:"-"`
Data json.RawMessage `json:"data,omitempty"`
Hash [sha256.Size]byte `json:"-"`
// contains filtered or unexported fields
}
Result struct contains the output of the GraphQL function this includes resulting json from the database query and any error information
func (*Result) CacheControl ¶ added in v0.16.44
func (*Result) OperationName ¶
type Role ¶
type Role struct {
Name string
Match string `jsonschema:"title=Related To,example=other_table.id_column,example=users.id"`
Tables []RoleTable `jsonschema:"title=Table Configuration for Role"`
// contains filtered or unexported fields
}
Configuration for user role
type RoleTable ¶
type RoleTable struct {
Name string
Schema string
ReadOnly bool `mapstructure:"read_only" jsonschema:"title=Read Only"`
Query *Query
Insert *Insert
Update *Update
Upsert *Upsert
Delete *Delete
}
Table configuration for a specific role (user role)
type Table ¶
type Table struct {
Name string
Schema string
Table string // Inherits Table
Type string
Blocklist []string
Columns []Column
// Permitted order by options
OrderBy map[string][]string `mapstructure:"order_by" jsonschema:"title=Order By Options,example=created_at desc"`
}
Configuration for a database table