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/v4/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 (BlockQueryWithRoles)
    Output:
    
    {"users": null}
    
    Example (BulkInsert)
    Output:
    
    {"users": [{"id": 1002, "email": "user1002@test.com"}, {"id": 1003, "email": "user1003@test.com"}]}
    
    Example (Insert)
    Output:
    
    {"users": [{"id": 1001, "email": "user1001@test.com"}]}
    
    Example (InsertIntoMultipleRelatedTables1)
    Output:
    
    {"purchases": [{"product": {"id": 2002, "name": "Product 2002", "price": 2012.5}, "customer": {"id": 1004, "email": "user1004@test.com", "full_name": "User 1004"}, "quantity": 5}]}
    
    Example (InsertIntoMultipleRelatedTables2)
    Output:
    
    {"users": [{"id": 1005, "email": "user1005@test.com", "products": [{"id": 2003, "name": "Product 2003", "price": 2013.5}], "full_name": "User 1005"}]}
    
    Example (InsertIntoMultipleRelatedTables3)
    Output:
    
    {"products": [{"id": 2004, "name": "Product 2004", "owner": {"id": 1006, "email": "user1006@test.com", "full_name": "User 1006"}}]}
    
    Example (InsertIntoRecursiveRelationship)
    Output:
    
    {"comments": [{"id": 5001, "reply_to_id": null}, {"id": 5002, "reply_to_id": 5001}]}
    
    Example (InsertIntoRecursiveRelationshipAndConnectTable1)
    Output:
    
    {"comments": [{"id": 5003, "reply_to_id": null}, {"id": 5, "reply_to_id": 5003}]}
    
    Example (InsertIntoRecursiveRelationshipAndConnectTable2)
    Output:
    
    {"comments": {"id": 5004, "product": {"id": 26}, "comments": [{"id": 6}], "commenter": {"id": 3}}}
    
    Example (InsertIntoTableAndConnectToRelatedTableWithArrayColumn)
    Output:
    
    {"products": [{"id": 2006, "name": "Product 2006", "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"}]}]}
    
    Example (InsertIntoTableAndConnectToRelatedTables)
    Output:
    
    {"products": [{"id": 2005, "name": "Product 2005", "owner": {"id": 6, "email": "user6@test.com", "full_name": "User 6"}}]}
    
    Example (InsertWithPresets)
    Output:
    
    {"products": [{"id": 2001, "name": "Product 2001", "owner": {"id": 3, "email": "user3@test.com"}}]}
    
    Example (Query)
    Output:
    
    {"products": [{"id": 1, "owner": {"id": 1, "fullName": "User 1"}}, {"id": 2, "owner": {"id": 2, "fullName": "User 2"}}, {"id": 3, "owner": {"id": 3, "fullName": "User 3"}}]}
    
    Example (QueryByID)
    Output:
    
    {"products": {"id": 2, "name": "Product 2"}}
    
    Example (QueryBySearch)
    Output:
    
    {"products": [{"id": 3, "name": "Product 3"}]}
    
    Example (QueryChildrenWithParent)
    Output:
    
    {"products": [{"name": "Product 1", "owner": {"email": "user1@test.com"}, "price": 11.5}, {"name": "Product 2", "owner": {"email": "user2@test.com"}, "price": 12.5}]}
    
    Example (QueryManyToManyViaJoinTable1)
    Output:
    
    {"products": [{"name": "Product 1", "owner": {"email": "user1@test.com"}, "customer": [{"email": "user2@test.com"}]}, {"name": "Product 2", "owner": {"email": "user2@test.com"}, "customer": [{"email": "user3@test.com"}]}]}
    
    Example (QueryManyToManyViaJoinTable2)
    Output:
    
    {"users": [{"email": "user1@test.com", "products": [{"name": "Product 1"}], "full_name": "User 1"}, {"email": "user2@test.com", "products": [{"name": "Product 2"}], "full_name": "User 2"}]}
    
    Example (QueryParentAndChildrenViaArrayColumn)
    Output:
    
    {"products": [{"name": "Product 1", "price": 11.5, "categories": [{"id": 1, "name": "Category 1"}, {"id": 2, "name": "Category 2"}]}, {"name": "Product 2", "price": 12.5, "categories": [{"id": 1, "name": "Category 1"}, {"id": 2, "name": "Category 2"}]}], "categories": [{"name": "Category 1", "products": [{"name": "Product 1"}, {"name": "Product 2"}]}, {"name": "Category 2", "products": [{"name": "Product 1"}, {"name": "Product 2"}]}]}
    
    Example (QueryParentsWithChildren)
    Output:
    
    {"users": [{"email": "user1@test.com", "products": [{"name": "Product 1", "price": 11.5}]}, {"email": "user2@test.com", "products": [{"name": "Product 2", "price": 12.5}]}]}
    
    Example (QueryWithAggregation)
    Output:
    
    {"products": [{"count_id": 100}]}
    
    Example (QueryWithAggregationBlockedColumn)
    Output:
    
    column blocked: sum (anon)
    
    Example (QueryWithAlternateFieldNames)
    Output:
    
    {"comments": [{"id": 1, "commenter": {"email": "user1@test.com"}}, {"id": 2, "commenter": {"email": "user2@test.com"}}]}
    
    Example (QueryWithCursorPagination)
    Output:
    
    [{"name": "Product 100"}, {"name": "Product 99"}, {"name": "Product 98"}]
    
    Example (QueryWithDynamicOrderBy)
    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)
    Output:
    
    {"users": [{"id": 1, "email": "user1@test.com", "full_name": "User 1", "stripe_id": "payment_id_1001"}, {"id": 2, "email": "user2@test.com", "full_name": "User 2", "stripe_id": "payment_id_1002"}]}
    
    Example (QueryWithFragments2)
    Output:
    
    {"users": [{"id": 1, "email": "user1@test.com", "full_name": "User 1", "stripe_id": "payment_id_1001"}, {"id": 2, "email": "user2@test.com", "full_name": "User 2", "stripe_id": "payment_id_1002"}]}
    
    Example (QueryWithFragments3)
    Output:
    
    {"users": [{"id": 1, "email": "user1@test.com", "full_name": "User 1", "stripe_id": "payment_id_1001"}, {"id": 2, "email": "user2@test.com", "full_name": "User 2", "stripe_id": "payment_id_1002"}]}
    
    Example (QueryWithFunctionsBlocked)
    Output:
    
    functions blocked: price (anon)
    
    Example (QueryWithFunctionsWithWhere)
    Output:
    
    {"products": [{"max_price": 110.5}]}
    
    Example (QueryWithJsonColumn)
    Output:
    
    {"users": {"id": 1, "category_counts": [{"count": 400, "category": {"name": "Category 1"}}, {"count": 600, "category": {"name": "Category 2"}}]}}
    
    Example (QueryWithLimitOffsetOrderByDistinctAndWhere)
    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)
    Output:
    
    {"users": {"id": 1, "email": "user1@test.com"}, "products": {"id": 1, "name": "Product 1", "customer": [{"email": "user2@test.com"}]}, "purchases": {"id": 1}}
    
    Example (QueryWithRecursiveRelationship1)
    Output:
    
    {"reply": {"id": 50, "comments": [{"id": 49}, {"id": 48}, {"id": 47}, {"id": 46}, {"id": 45}]}}
    
    Example (QueryWithRecursiveRelationship2)
    Output:
    
    {"comments": {"id": 95, "replies": [{"id": 96}, {"id": 97}, {"id": 98}, {"id": 99}, {"id": 100}]}}
    
    Example (QueryWithRecursiveRelationshipAndAggregations)
    Output:
    
    {"comments": {"id": 95, "replies": [{"count_id": 5}]}}
    
    Example (QueryWithRemoteAPIJoin)
    Output:
    
    {"users": [{"email": "user1@test.com", "payments":[{"desc":"Payment 1 for payment_id_1001"},{"desc": "Payment 2 for payment_id_1001"}]}, {"email": "user2@test.com", "payments":[{"desc":"Payment 1 for payment_id_1002"},{"desc": "Payment 2 for payment_id_1002"}]}]}
    
    Example (QueryWithSkipAndIncludeDirectives)
    Output:
    
    {"users": [], "products": [{"id": 1, "name": "Product 1"}, {"id": 2, "name": "Product 2"}]}
    
    Example (QueryWithSkippingAuthRequiredSelectors)
    Output:
    
    {"products": [{"id": 1, "name": "Product 1", "owner": null}, {"id": 2, "name": "Product 2", "owner": null}]}
    
    Example (QueryWithSyntheticTables)
    Output:
    
    {"me": {"email": "user1@test.com"}}
    
    Example (QueryWithUnionForPolymorphicRelationships)
    Output:
    
    {"notifications": [{"id": 1, "verb": "Joined", "subject": {"email": "user1@test.com"}}, {"id": 2, "verb": "Bought", "subject": {"name": "Product 2"}}]}
    
    Example (QueryWithUser)
    Output:
    
    {"products": [{"id": 31, "owner": {"id": 31}}]}
    
    Example (QueryWithVariables)
    Output:
    
    {"products": {"id": 70, "name": "Product 70"}}
    
    Example (QueryWithView)
    Output:
    
    {"hot_products": [{"product": {"id": 51, "name": "Product 51"}}, {"product": {"id": 52, "name": "Product 52"}}, {"product": {"id": 53, "name": "Product 53"}}]}
    
    Example (QueryWithWhereGreaterThanOrLesserThan)
    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 (QueryWithWhereIn)
    Output:
    
    {"products": [{"id": 1}, {"id": 2}, {"id": 3}]}
    
    Example (QueryWithWhereNotIsNullAndGreaterThan)
    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)
    Output:
    
    {"products": [{"id": 4, "owner": {"id": 4, "email": "user4@test.com"}}]}
    
    Example (Subscription)
    Output:
    
    {"users": {"id": 3, "email": "user3@test.com", "phone": null}}
    {"users": {"id": 3, "email": "user3@test.com", "phone": "650-447-0000"}}
    {"users": {"id": 3, "email": "user3@test.com", "phone": "650-447-0001"}}
    {"users": {"id": 3, "email": "user3@test.com", "phone": "650-447-0002"}}
    {"users": {"id": 3, "email": "user3@test.com", "phone": "650-447-0003"}}
    {"users": {"id": 3, "email": "user3@test.com", "phone": "650-447-0004"}}
    {"users": {"id": 3, "email": "user3@test.com", "phone": "650-447-0005"}}
    {"users": {"id": 3, "email": "user3@test.com", "phone": "650-447-0006"}}
    {"users": {"id": 3, "email": "user3@test.com", "phone": "650-447-0007"}}
    {"users": {"id": 3, "email": "user3@test.com", "phone": "650-447-0008"}}
    
    Example (SubscriptionWithCursor)
    Output:
    
    {"chats": [{"id": 1, "body": "This is chat message number 1"}, {"id": 2, "body": "This is chat message number 2"}, {"id": 3, "body": "This is chat message number 3"}], "chats_cursor_was_here"}
    {"chats": [{"id": 4, "body": "This is chat message number 4"}], "chats_cursor_was_here"}
    {"chats": [{"id": 5, "body": "This is chat message number 5"}], "chats_cursor_was_here"}
    {"chats": [{"id": 6, "body": "New chat message 6"}], "chats_cursor_was_here"}
    {"chats": [{"id": 7, "body": "New chat message 7"}], "chats_cursor_was_here"}
    {"chats": [{"id": 8, "body": "New chat message 8"}], "chats_cursor_was_here"}
    {"chats": [{"id": 9, "body": "New chat message 9"}], "chats_cursor_was_here"}
    {"chats": [{"id": 10, "body": "New chat message 10"}], "chats_cursor_was_here"}
    {"chats": [{"id": 11, "body": "New chat message 11"}], "chats_cursor_was_here"}
    {"chats": [{"id": 12, "body": "New chat message 12"}], "chats_cursor_was_here"}
    {"chats": [{"id": 13, "body": "New chat message 13"}], "chats_cursor_was_here"}
    {"chats": [{"id": 14, "body": "New chat message 14"}], "chats_cursor_was_here"}
    {"chats": [{"id": 15, "body": "New chat message 15"}], "chats_cursor_was_here"}
    
    Example (Update)
    Output:
    
    {"products": {"id": 100, "name": "Updated Product 100"}}
    
    Example (UpdateMultipleRelatedTables1)
    Output:
    
    {"purchases": {"product": {"description": "Updated product related to purchase 100"}, "customer": {"full_name": "Updated user related to purchase 100"}, "quantity": 6}}
    
    Example (UpdateTableAndConnectToRelatedTables)
    Output:
    
    {"users": {"products": [{"id": 99}], "full_name": "Updated user 100"}}
    
    Example (UpdateTableAndRelatedTable)
    Output:
    
    {"users": {"products": [{"id": 90}], "full_name": "Updated user 90"}}
    
    Example (VeryComplexQuery)
    Output:
    
    {"products": [{"id": 27, "name": "Product 27", "owner": {"email": "user27@test.com", "picture": null, "full_name": "User 27", "category_counts": [{"count": 400, "category": {"name": "Category 1"}}, {"count": 600, "category": {"name": "Category 2"}}]}, "price": 37.5, "category": [{"id": 1, "name": "Category 1"}, {"id": 2, "name": "Category 2"}]}]}
    

    Index

    Examples

    Constants

    View Source
    const (
    	// Name of the authentication provider. Eg. google, github, etc
    	UserIDProviderKey contextkey = iota
    
    	// 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

      This section is empty.

      Functions

      This section is empty.

      Types

      type Column

      type Column struct {
      	ID         int32
      	Name       string
      	Type       string
      	Primary    bool
      	Array      bool
      	ForeignKey string `mapstructure:"related_to"`
      }

        Column struct defines a database column

        type Config

        type Config struct {
        	// SecretKey is used to encrypt opaque values such as
        	// the cursor. Auto-generated if not set
        	SecretKey string `mapstructure:"secret_key"`
        
        	// DisableAllowList when set to true entirely disables the
        	// allow list workflow and all queries are always compiled
        	// even in production. (Warning possible security concern)
        	DisableAllowList bool `mapstructure:"disable_allow_list"`
        
        	// AllowListPath if the path to allow list file if not set the
        	// path is assumed to be the same as the config path
        	AllowListPath string `mapstructure:"allow_list_path"`
        	// SetUserID forces the database session variable `user.id` to
        	// be set to the user id. This variables can be used by triggers
        	// or other database functions
        	SetUserID bool `mapstructure:"set_user_id"`
        
        	// DefaultBlock ensures that in anonymous mode (role 'anon') all tables
        	// are blocked from queries and mutations. To open access to tables in
        	// anonymous mode they have to be added to the 'anon' role config.
        	DefaultBlock bool `mapstructure:"default_block"`
        
        	// Vars is a map of hardcoded 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"`
        
        	// HeaderVars is a map of dynamic variables that map to http header
        	// values.
        	HeaderVars map[string]string `mapstructure:"header_variables"`
        
        	// Blocklist is a list of tables and columns that should be filtered
        	// out from any and all queries
        	Blocklist []string
        
        	// Resolvers contain the configs for custom resolvers. For example the `remote_api`
        	// resolver would join json from a remote API into your query response.
        	Resolvers []ResolverConfig
        
        	// Tables contains all table specific configuration such as aliased tables
        	// creating relationships between tables, etc
        	Tables []Table
        
        	// RolesQuery if set enabled attributed based access control. This query
        	// is used to fetch the user attributes that then dynamically define the users
        	// role.
        	RolesQuery string `mapstructure:"roles_query"`
        
        	// Roles contains all the configuration for all the roles you want to support
        	// `user` and `anon` are two default roles. User role is for when a user ID is
        	// available and Anon when it's not.
        	//
        	// If you're using the RolesQuery config to enable atribute based acess control then
        	// you can 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"`
        
        	// Disable inflections. Inflections are deprecated and will be
        	// removed in next major version.
        	EnableInflection bool `mapstructure:"enable_inflection"`
        
        	// Customize singular suffix
        	// By default is set to "ById"
        	SingularSuffix string `mapstructure:"singular_suffix"`
        
        	// Database type name. Defaults to 'postgres' (options: mysql, postgres)
        	DBType string `mapstructure:"db_type"`
        
        	// Log warnings and other debug information
        	Debug bool
        
        	// Subscriptions poll the database to query for updates
        	// this sets the duration (in seconds) between requests.
        	// Defaults to 5 seconds
        	PollDuration time.Duration `mapstructure:"poll_every_seconds"`
        
        	// DefaultLimit sets the default max limit (number of rows) when a
        	// limit is not defined in the query or the table role config.
        	// Default to 20
        	DefaultLimit int `mapstructure:"default_limit"`
        
        	// Enable production mode. This defaults to true if GO_ENV is set to
        	// "production". When this is true the allow list is enforced.
        	Production bool
        	// contains filtered or unexported fields
        }

          Core struct contains core specific config value

          func ReadInConfig

          func ReadInConfig(configFile string) (*Config, error)

            ReadInConfig function 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 (*Config) AddRoleTable

            func (c *Config) AddRoleTable(role, table string, conf interface{}) error

              AddRoleTable function is a helper function to make it easy to add per-table row-level config

              func (*Config) RemoveRoleTable

              func (c *Config) RemoveRoleTable(role, table string) error

              func (*Config) SetResolver

              func (c *Config) SetResolver(name string, fn refunc) error

              type Delete

              type Delete struct {
              	Filters []string
              	Columns []string
              	Block   bool
              }

                Delete struct contains access control values for delete operations

                type Error

                type Error struct {
                	Message string `json:"message"`
                }

                type GraphJin

                type GraphJin struct {
                	// contains filtered or unexported fields
                }

                  GraphJin struct is an instance of the GraphJin engine it holds all the required information like datase schemas, relationships, etc that the GraphQL to SQL compiler would need to do it's job.

                  func NewGraphJin

                  func NewGraphJin(conf *Config, db *sql.DB) (*GraphJin, error)

                    NewGraphJin creates the GraphJin struct, this involves querying the database to learn its schemas and relationships

                    func (*GraphJin) GraphQL

                    func (gj *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) IsProd

                      func (gj *GraphJin) IsProd() bool

                      func (*GraphJin) Subscribe

                      func (gj *GraphJin) Subscribe(
                      	c context.Context,
                      	query string,
                      	vars json.RawMessage,
                      	rc *ReqConfig) (*Member, error)

                        GraphQLEx is the extended version of the Subscribe function allowing for request specific config.

                        type Insert

                        type Insert struct {
                        	Filters []string
                        	Columns []string
                        	Presets map[string]string
                        	Block   bool
                        }

                          Insert struct contains access control values for insert operations

                          type Member

                          type Member struct {
                          	Result chan *Result
                          	// contains filtered or unexported fields
                          }

                          func (*Member) String

                          func (m *Member) String() string

                          func (*Member) Unsubscribe

                          func (m *Member) Unsubscribe()

                          type OpType

                          type OpType int
                          const (
                          	OpUnknown OpType = iota
                          	OpQuery
                          	OpSubscription
                          	OpMutation
                          )

                          func Operation

                          func Operation(query string) (OpType, string)

                            Operation function return the operation type and name from the query. It uses a very fast algorithm to extract the operation without having to parse the query.

                            type Query

                            type Query struct {
                            	Limit            int
                            	Filters          []string
                            	Columns          []string
                            	DisableFunctions bool `mapstructure:"disable_functions"`
                            	Block            bool
                            }

                              Query struct contains access control values for query operations

                              type ReqConfig

                              type ReqConfig struct {
                              	APQKey string
                              	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

                                type Resolver interface {
                                	Resolve(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

                                  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

                                    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

                                      type ResolverReq struct {
                                      	ID  string
                                      	Sel *qcode.Select
                                      	Log *log.Logger
                                      	*ReqConfig
                                      }

                                      type Result

                                      type Result struct {
                                      	Errors     []Error         `json:"errors,omitempty"`
                                      	Data       json.RawMessage `json:"data,omitempty"`
                                      	Extensions *extensions     `json:"extensions,omitempty"`
                                      	// 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

                                        func (r *Result) CacheControl() string

                                        func (*Result) Operation

                                        func (r *Result) Operation() OpType

                                        func (*Result) OperationName

                                        func (r *Result) OperationName() string

                                        func (*Result) QueryName

                                        func (r *Result) QueryName() string

                                        func (*Result) Role

                                        func (r *Result) Role() string

                                        func (*Result) SQL

                                        func (r *Result) SQL() string

                                        type Role

                                        type Role struct {
                                        	Name   string
                                        	Match  string
                                        	Tables []RoleTable
                                        	// contains filtered or unexported fields
                                        }

                                          Role struct contains role specific access control values for for all database tables

                                          func (*Role) GetTable

                                          func (r *Role) GetTable(schema, name string) *RoleTable

                                          type RoleTable

                                          type RoleTable struct {
                                          	Name     string
                                          	Schema   string
                                          	ReadOnly bool `mapstructure:"read_only"`
                                          
                                          	Query  *Query
                                          	Insert *Insert
                                          	Update *Update
                                          	Upsert *Upsert
                                          	Delete *Delete
                                          }

                                            RoleTable struct contains role specific access control values for a database table

                                            type Table

                                            type Table struct {
                                            	Name      string
                                            	Schema    string
                                            	Table     string
                                            	Type      string
                                            	Blocklist []string
                                            	Columns   []Column
                                            	OrderBy   map[string][]string `mapstructure:"order_by"`
                                            }

                                              Table struct defines a database table

                                              type Update

                                              type Update struct {
                                              	Filters []string
                                              	Columns []string
                                              	Presets map[string]string
                                              	Block   bool
                                              }

                                                Insert struct contains access control values for update operations

                                                type Upsert

                                                type Upsert struct {
                                                	Filters []string
                                                	Columns []string
                                                	Presets map[string]string
                                                	Block   bool
                                                }

                                                Directories

                                                Path Synopsis
                                                internal
                                                crypto
                                                Provides symmetric authenticated encryption using 256-bit AES-GCM with a random nonce.
                                                Provides symmetric authenticated encryption using 256-bit AES-GCM with a random nonce.