Documentation
¶
Index ¶
- Constants
- func NewXidMetadata() *xidMetadata
- func RewriteUpsertQueryFromMutation(m schema.Mutation, authRw *authRewriter, mutationQueryVar string, ...) []*dql.GraphQuery
- type AddRewriter
- func (arw *AddRewriter) FromMutationResult(ctx context.Context, mutation schema.Mutation, assigned map[string]string, ...) ([]*dql.GraphQuery, error)
- func (arw *AddRewriter) MutatedRootUIDs(mutation schema.Mutation, assigned map[string]string, ...) []string
- func (arw *AddRewriter) Rewrite(ctx context.Context, m schema.Mutation, idExistence map[string]string) ([]*UpsertMutation, error)
- func (arw *AddRewriter) RewriteQueries(ctx context.Context, m schema.Mutation) ([]*dql.GraphQuery, []string, error)
- type CompletionFunc
- type DgraphExecutor
- type DgraphExecutorFunc
- type MutationMiddleware
- type MutationMiddlewares
- type MutationResolver
- func AclOnlyMW4Mutation(resolver MutationResolver) MutationResolver
- func GuardianAuthMW4Mutation(resolver MutationResolver) MutationResolver
- func GuardianOfTheGalaxyAuthMW4Mutation(resolver MutationResolver) MutationResolver
- func IpWhitelistingMW4Mutation(resolver MutationResolver) MutationResolver
- func LoggingMWMutation(resolver MutationResolver) MutationResolver
- func NewDgraphResolver(mr MutationRewriter, ex DgraphExecutor) MutationResolver
- func NewHTTPMutationResolver(hc *http.Client) MutationResolver
- type MutationResolverFunc
- type MutationRewriter
- type MutationType
- type QueryMiddleware
- type QueryMiddlewares
- type QueryResolver
- func GuardianAuthMW4Query(resolver QueryResolver) QueryResolver
- func GuardianOfTheGalaxyAuthMW4Query(resolver QueryResolver) QueryResolver
- func IpWhitelistingMW4Query(resolver QueryResolver) QueryResolver
- func LoggingMWQuery(resolver QueryResolver) QueryResolver
- func NewCustomDQLQueryResolver(ex DgraphExecutor) QueryResolver
- func NewEntitiesQueryResolver(qr QueryRewriter, ex DgraphExecutor) QueryResolver
- func NewHTTPQueryResolver(hc *http.Client) QueryResolver
- func NewQueryResolver(qr QueryRewriter, ex DgraphExecutor) QueryResolver
- type QueryResolverFunc
- type QueryRewriter
- type RequestResolver
- type Resolved
- type ResolverFactory
- type ResolverFns
- type ResultCompleter
- type Rewriter
- type UpdateRewriter
- func (urw *UpdateRewriter) FromMutationResult(ctx context.Context, mutation schema.Mutation, assigned map[string]string, ...) ([]*dql.GraphQuery, error)
- func (urw *UpdateRewriter) MutatedRootUIDs(mutation schema.Mutation, assigned map[string]string, ...) []string
- func (urw *UpdateRewriter) Rewrite(ctx context.Context, m schema.Mutation, idExistence map[string]string) ([]*UpsertMutation, error)
- func (urw *UpdateRewriter) RewriteQueries(ctx context.Context, m schema.Mutation) ([]*dql.GraphQuery, []string, error)
- type UpsertMutation
- type VariableGenerator
Constants ¶
const ( MutationQueryVar = "x" MutationQueryVarUID = "uid(x)" )
const (
ErrInternal = "Internal error"
)
Variables ¶
This section is empty.
Functions ¶
func NewXidMetadata ¶
func NewXidMetadata() *xidMetadata
NewXidMetadata returns a new empty *xidMetadata for storing the metadata.
Types ¶
type AddRewriter ¶
type AddRewriter struct {
Rewriter
// contains filtered or unexported fields
}
func (*AddRewriter) FromMutationResult ¶
func (arw *AddRewriter) FromMutationResult( ctx context.Context, mutation schema.Mutation, assigned map[string]string, result map[string]interface{}) ([]*dql.GraphQuery, error)
FromMutationResult rewrites the query part of a GraphQL add mutation into a Dgraph query.
func (*AddRewriter) MutatedRootUIDs ¶
func (*AddRewriter) Rewrite ¶
func (arw *AddRewriter) Rewrite( ctx context.Context, m schema.Mutation, idExistence map[string]string) ([]*UpsertMutation, error)
Rewrite takes a GraphQL schema.Mutation add and builds a Dgraph upsert mutation. m must have a single argument called 'input' that carries the mutation data. The arguments also consist of idExistence map which is a map from Variable Name --> UID . This map is used to know which referenced nodes exists and whether to link the newly created node to existing node or create a new one.
That argument could have been passed in the mutation like:
addPost(input: { title: "...", ... })
or be passed in a GraphQL variable like:
addPost(input: $newPost)
Either way, the data needs to have type information added and have some rewriting done - for example, rewriting field names from the GraphQL view to what's stored in Dgraph, and rewriting ID fields from their names to uid.
For example, a GraphQL add mutation to add an object of type Author, with GraphQL input object (where country code is @id) :
{
name: "A.N. Author",
country: { code: "ind", name: "India" },
posts: [ { title: "A Post", text: "Some text" }]
friends: [ { id: "0x123" } ]
}
and idExistence
{
"Country2": "0x234",
"Person3": "0x123"
}
becomes an unconditional mutation.
{
"uid":"_:Author1",
"dgraph.type":["Author"],
"Author.name":"A.N. Author",
"Author.country": {
"uid":"0x234"
},
"Author.posts": [ {
"uid":"_:Post3"
"dgraph.type":["Post"],
"Post.text":"Some text",
"Post.title":"A Post",
} ],
"Author.friends":[ {"uid":"0x123"} ],
}
func (*AddRewriter) RewriteQueries ¶
func (arw *AddRewriter) RewriteQueries( ctx context.Context, m schema.Mutation) ([]*dql.GraphQuery, []string, error)
RewriteQueries takes a GraphQL schema.Mutation add and creates queries to find out if referenced nodes by XID and UID exist or not. m must have a single argument called 'input' that carries the mutation data.
For example, a GraphQL add mutation to add an object of type Author, with GraphQL input object (where country code is @id)
{
name: "A.N. Author",
country: { code: "ind", name: "India" },
posts: [ { title: "A Post", text: "Some text" }]
friends: [ { id: "0x123" } ]
}
The following queries would be generated
query {
Country2(func: eq(Country.code, "ind")) @filter(type: Country) {
uid
}
Person3(func: uid(0x123)) @filter(type: Person) {
uid
}
}
This query will be executed and depending on the result it would be decided whether to create a new country as part of this mutation or link it to an existing country. If it is found out that there is an existing country, no modifications are made to the country's attributes and its children. Mutations of the country's children are simply ignored. If it is found out that the Person with id 0x123 does not exist, the corresponding mutation will fail.
type CompletionFunc ¶
CompletionFunc is an adapter that allows us to compose completions and build a ResultCompleter from a function. Based on the http.HandlerFunc pattern.
type DgraphExecutor ¶
type DgraphExecutor interface {
// Execute performs the actual query/mutation and returns a Dgraph response. If an error
// occurs, that indicates that the execution failed in some way significant enough
// way as to not continue processing this query/mutation or others in the same request.
Execute(ctx context.Context, req *dgoapi.Request, field schema.Field) (*dgoapi.Response, error)
CommitOrAbort(ctx context.Context, tc *dgoapi.TxnContext) (*dgoapi.TxnContext, error)
}
A DgraphExecutor can execute a query/mutation and returns the request response and any errors.
func NewAdminExecutor ¶
func NewAdminExecutor() DgraphExecutor
NewAdminExecutor builds a DgraphExecutor for proxying requests through dgraph.
func NewDgraphExecutor ¶
func NewDgraphExecutor() DgraphExecutor
NewDgraphExecutor builds a DgraphExecutor for proxying requests through dgraph.
type DgraphExecutorFunc ¶
DgraphExecutorFunc is an adapter that allows us to compose dgraph execution and build a QueryExecuter from a function. Based on the http.HandlerFunc pattern.
type MutationMiddleware ¶
type MutationMiddleware func(resolver MutationResolver) MutationResolver
MutationMiddleware represents a middleware for mutations
type MutationMiddlewares ¶
type MutationMiddlewares []MutationMiddleware
MutationMiddlewares represents a list of middlewares for mutations, that get applied in the order they are present in the list. Inspired from: https://github.com/justinas/alice
func (MutationMiddlewares) Then ¶
func (mws MutationMiddlewares) Then(resolver MutationResolver) MutationResolver
Then chains the middlewares and returns the final MutationResolver.
MutationMiddlewares{m1, m2, m3}.Then(r)
is equivalent to:
m1(m2(m3(r)))
When the request comes in, it will be passed to m1, then m2, then m3 and finally, the given resolverFunc (assuming every middleware calls the following one).
A chain can be safely reused by calling Then() several times.
commonMiddlewares := MutationMiddlewares{authMiddleware, loggingMiddleware}
backupResolver = commonMiddlewares.Then(resolveBackup)
configResolver = commonMiddlewares.Then(resolveConfig)
Note that middlewares are called on every call to Then() and thus several instances of the same middleware will be created when a chain is reused in this way. For proper middleware, this should cause no problems.
Then() treats nil as a MutationResolverFunc that resolves to (&Resolved{Field: mutation}, true)
type MutationResolver ¶
type MutationResolver interface {
Resolve(ctx context.Context, mutation schema.Mutation) (*Resolved, bool)
}
A MutationResolver can resolve a single mutation.
func AclOnlyMW4Mutation ¶
func AclOnlyMW4Mutation(resolver MutationResolver) MutationResolver
func GuardianAuthMW4Mutation ¶
func GuardianAuthMW4Mutation(resolver MutationResolver) MutationResolver
GuardianAuthMW4Mutation blocks the resolution of resolverFunc if there is no Guardian auth present in context, otherwise it lets the resolverFunc resolve the mutation.
func GuardianOfTheGalaxyAuthMW4Mutation ¶
func GuardianOfTheGalaxyAuthMW4Mutation(resolver MutationResolver) MutationResolver
GuardianOfTheGalaxyAuthMW4Mutation blocks the resolution of resolverFunc if there is no Guardian of Galaxy auth present in context, otherwise it lets the resolverFunc resolve the mutation.
func IpWhitelistingMW4Mutation ¶
func IpWhitelistingMW4Mutation(resolver MutationResolver) MutationResolver
func LoggingMWMutation ¶
func LoggingMWMutation(resolver MutationResolver) MutationResolver
func NewDgraphResolver ¶
func NewDgraphResolver(mr MutationRewriter, ex DgraphExecutor) MutationResolver
NewDgraphResolver creates a new mutation resolver. The resolver runs the pipeline: 1) rewrite the mutation using mr (return error if failed) 2) execute the mutation with me (return error if failed) 3) write a query for the mutation with mr (return error if failed) 4) execute the query with qe (return error if failed)
func NewHTTPMutationResolver ¶
func NewHTTPMutationResolver(hc *http.Client) MutationResolver
NewHTTPMutationResolver creates a resolver that resolves GraphQL mutation from an HTTP endpoint
type MutationResolverFunc ¶
MutationResolverFunc is an adapter that allows to build a MutationResolver from a function. Based on the http.HandlerFunc pattern.
type MutationRewriter ¶
type MutationRewriter interface {
// RewriteQueries generates and rewrites GraphQL mutation m into DQL queries which
// check if any referenced node by XID or ID exist or not.
// Instead of filtering on dgraph.type like @filter(type(Parrot)), we query `dgraph.type` and
// filter it on GraphQL side. @filter(type(Parrot)) is costly in terms of memory and cpu.
// Example existence queries:
// 1. Parrot1(func: uid(0x127)) {
// uid
// dgraph.type
// }
// 2. Computer2(func: eq(Computer.name, "computer1")) {
// uid
// dgraph.type
// }
// These query will be created in case of Add or Update Mutation which references node
// 0x127 or Computer of name "computer1"
RewriteQueries(ctx context.Context, m schema.Mutation) ([]*dql.GraphQuery, []string, error)
// Rewrite rewrites GraphQL mutation m into a Dgraph mutation - that could
// be as simple as a single DelNquads, or could be a Dgraph upsert mutation
// with a query and multiple mutations guarded by conditions.
Rewrite(ctx context.Context, m schema.Mutation, idExistence map[string]string) ([]*UpsertMutation, error)
// FromMutationResult takes a GraphQL mutation and the results of a Dgraph
// mutation and constructs a Dgraph query. It's used to find the return
// value from a GraphQL mutation - i.e. we've run the mutation indicated by m
// now we need to query Dgraph to satisfy all the result fields in m.
FromMutationResult(
ctx context.Context,
m schema.Mutation,
assigned map[string]string,
result map[string]interface{}) ([]*dql.GraphQuery, error)
// MutatedRootUIDs returns a list of Root UIDs that were mutated as part of the mutation.
MutatedRootUIDs(
mutation schema.Mutation,
assigned map[string]string,
result map[string]interface{}) []string
}
A MutationRewriter can transform a GraphQL mutation into a Dgraph mutation and can build a Dgraph dql.GraphQuery to follow a GraphQL mutation.
Mutations come in like:
mutation addAuthor($auth: AuthorInput!) {
addAuthor(input: $auth) {
author {
id
name
}
}
}
Where `addAuthor(input: $auth)` implies a mutation that must get run - written to a Dgraph mutation by Rewrite. The GraphQL following `addAuthor(...)`implies a query to run and return the newly created author, so the mutation query rewriting is dependent on the context set up by the result of the mutation.
func NewAddRewriter ¶
func NewAddRewriter() MutationRewriter
NewAddRewriter returns new MutationRewriter for add & update mutations.
func NewDeleteRewriter ¶
func NewDeleteRewriter() MutationRewriter
NewDeleteRewriter returns new MutationRewriter for delete mutations..
func NewUpdateRewriter ¶
func NewUpdateRewriter() MutationRewriter
NewUpdateRewriter returns new MutationRewriter for add & update mutations.
type MutationType ¶
type MutationType int
Enum passed on to rewriteObject function.
const ( // Add Mutation Add MutationType = iota // Add Mutation with Upsert AddWithUpsert // Update Mutation used for to setting new nodes, edges. UpdateWithSet // Update Mutation used for removing edges. UpdateWithRemove )
type QueryMiddleware ¶
type QueryMiddleware func(resolver QueryResolver) QueryResolver
QueryMiddleware represents a middleware for queries
type QueryMiddlewares ¶
type QueryMiddlewares []QueryMiddleware
QueryMiddlewares represents a list of middlewares for queries, that get applied in the order they are present in the list. Inspired from: https://github.com/justinas/alice
func (QueryMiddlewares) Then ¶
func (mws QueryMiddlewares) Then(resolver QueryResolver) QueryResolver
Then chains the middlewares and returns the final QueryResolver.
QueryMiddlewares{m1, m2, m3}.Then(r)
is equivalent to:
m1(m2(m3(r)))
When the request comes in, it will be passed to m1, then m2, then m3 and finally, the given resolverFunc (assuming every middleware calls the following one).
A chain can be safely reused by calling Then() several times.
commonMiddlewares := QueryMiddlewares{authMiddleware, loggingMiddleware}
healthResolver = commonMiddlewares.Then(resolveHealth)
stateResolver = commonMiddlewares.Then(resolveState)
Note that middlewares are called on every call to Then() and thus several instances of the same middleware will be created when a chain is reused in this way. For proper middleware, this should cause no problems.
Then() treats nil as a QueryResolverFunc that resolves to &Resolved{Field: query}
type QueryResolver ¶
A QueryResolver can resolve a single query.
func GuardianAuthMW4Query ¶
func GuardianAuthMW4Query(resolver QueryResolver) QueryResolver
GuardianAuthMW4Query blocks the resolution of resolverFunc if there is no Guardian auth present in context, otherwise it lets the resolverFunc resolve the query.
func GuardianOfTheGalaxyAuthMW4Query ¶
func GuardianOfTheGalaxyAuthMW4Query(resolver QueryResolver) QueryResolver
GuardianOfTheGalaxyAuthMW4Query blocks the resolution of resolverFunc if there is no Guardian of Galaxy auth present in context, otherwise it lets the resolverFunc resolve the query.
func IpWhitelistingMW4Query ¶
func IpWhitelistingMW4Query(resolver QueryResolver) QueryResolver
func LoggingMWQuery ¶
func LoggingMWQuery(resolver QueryResolver) QueryResolver
func NewCustomDQLQueryResolver ¶
func NewCustomDQLQueryResolver(ex DgraphExecutor) QueryResolver
func NewEntitiesQueryResolver ¶
func NewEntitiesQueryResolver(qr QueryRewriter, ex DgraphExecutor) QueryResolver
NewEntitiesQueryResolver creates a new query resolver for `_entities` query. It is introduced because result completion works little different for `_entities` query.
func NewHTTPQueryResolver ¶
func NewHTTPQueryResolver(hc *http.Client) QueryResolver
NewHTTPQueryResolver creates a resolver that can resolve GraphQL query from an HTTP endpoint
func NewQueryResolver ¶
func NewQueryResolver(qr QueryRewriter, ex DgraphExecutor) QueryResolver
NewQueryResolver creates a new query resolver. The resolver runs the pipeline: 1) rewrite the query using qr (return error if failed) 2) execute the rewritten query with ex (return error if failed) 3) process the result with rc
type QueryResolverFunc ¶
QueryResolverFunc is an adapter that allows to build a QueryResolver from a function. Based on the http.HandlerFunc pattern.
type QueryRewriter ¶
type QueryRewriter interface {
Rewrite(ctx context.Context, q schema.Query) ([]*dql.GraphQuery, error)
}
A QueryRewriter can build a Dgraph dql.GraphQuery from a GraphQL query,
func NewQueryRewriter ¶
func NewQueryRewriter() QueryRewriter
NewQueryRewriter returns a new QueryRewriter.
type RequestResolver ¶
type RequestResolver struct {
// contains filtered or unexported fields
}
RequestResolver can process GraphQL requests and write GraphQL JSON responses. A schema.Request may contain any number of queries or mutations (never both). RequestResolver.Resolve() resolves all of them by finding the resolved answers of the component queries/mutations and joining into a single schema.Response.
func New ¶
func New(s schema.Schema, resolverFactory ResolverFactory) *RequestResolver
New creates a new RequestResolver.
func (*RequestResolver) Resolve ¶
func (r *RequestResolver) Resolve(ctx context.Context, gqlReq *schema.Request) (resp *schema.Response)
Resolve processes r.GqlReq and returns a GraphQL response. r.GqlReq should be set with a request before Resolve is called and a schema and backend Dgraph should have been added. Resolve records any errors in the response's error field.
func (*RequestResolver) Schema ¶
func (r *RequestResolver) Schema() schema.Schema
func (*RequestResolver) ValidateSubscription ¶
func (r *RequestResolver) ValidateSubscription(req *schema.Request) error
ValidateSubscription will check the given subscription query is valid or not.
type Resolved ¶
A Resolved is the result of resolving a single field - generally a query or mutation.
type ResolverFactory ¶
type ResolverFactory interface {
// WithQueryResolver adds a new query resolver. Each time query name is resolved
// resolver is called to create a new instance of a QueryResolver to resolve the
// query.
WithQueryResolver(name string, resolver func(schema.Query) QueryResolver) ResolverFactory
// WithMutationResolver adds a new query resolver. Each time mutation name is resolved
// resolver is called to create a new instance of a MutationResolver to resolve the
// mutation.
WithMutationResolver(
name string, resolver func(schema.Mutation) MutationResolver) ResolverFactory
// WithConventionResolvers adds a set of our convention based resolvers to the
// factory. The registration happens only once.
WithConventionResolvers(s schema.Schema, fns *ResolverFns) ResolverFactory
// WithQueryMiddlewareConfig adds the configuration to use to apply middlewares before resolving
// queries. The config should be a mapping of the name of query to its middlewares.
WithQueryMiddlewareConfig(config map[string]QueryMiddlewares) ResolverFactory
// WithMutationMiddlewareConfig adds the configuration to use to apply middlewares before
// resolving mutations. The config should be a mapping of the name of mutation to its
// middlewares.
WithMutationMiddlewareConfig(config map[string]MutationMiddlewares) ResolverFactory
// WithSchemaIntrospection adds schema introspection capabilities to the factory.
// So __schema and __type queries can be resolved.
WithSchemaIntrospection() ResolverFactory
// contains filtered or unexported methods
}
A ResolverFactory finds the right resolver for a query/mutation.
func NewResolverFactory ¶
func NewResolverFactory( queryError QueryResolverFunc, mutationError MutationResolverFunc) ResolverFactory
NewResolverFactory returns a ResolverFactory that resolves requests via query/mutation rewriting and execution through Dgraph. If the factory gets asked to resolve a query/mutation it doesn't know how to rewrite, it uses the queryError/mutationError to build an error result.
type ResolverFns ¶
type ResolverFns struct {
Qrw QueryRewriter
Arw func() MutationRewriter
Urw func() MutationRewriter
Drw MutationRewriter
Ex DgraphExecutor
}
ResolverFns is a convenience struct for passing blocks of rewriters and executors.
type ResultCompleter ¶
A ResultCompleter can take a []byte slice representing an intermediate result in resolving field and applies a completion step.
type Rewriter ¶
type Rewriter struct {
// VarGen is the VariableGenerator used accross RewriteQueries and Rewrite functions
// for Mutation. It generates unique variable names for DQL queries and mutations.
VarGen *VariableGenerator
// XidMetadata stores data like seenUIDs and variableObjMap to be used across Rewrite
// and RewriteQueries functions for Mutations.
XidMetadata *xidMetadata
}
type UpdateRewriter ¶
type UpdateRewriter struct {
Rewriter
// contains filtered or unexported fields
}
func (*UpdateRewriter) FromMutationResult ¶
func (urw *UpdateRewriter) FromMutationResult( ctx context.Context, mutation schema.Mutation, assigned map[string]string, result map[string]interface{}) ([]*dql.GraphQuery, error)
FromMutationResult rewrites the query part of a GraphQL update mutation into a Dgraph query.
func (*UpdateRewriter) MutatedRootUIDs ¶
func (*UpdateRewriter) Rewrite ¶
func (urw *UpdateRewriter) Rewrite( ctx context.Context, m schema.Mutation, idExistence map[string]string) ([]*UpsertMutation, error)
Rewrite rewrites set and remove update patches into dql upsert mutations. The GraphQL updates look like:
input UpdateAuthorInput {
filter: AuthorFilter!
set: PatchAuthor
remove: PatchAuthor
}
which gets rewritten in to a Dgraph upsert mutation - filter becomes the query - set becomes the Dgraph set mutation - remove becomes the Dgraph delete mutation
The semantics is the same as the Dgraph mutation semantics.
- Any values in set become the new values for those predicates (or add to the existing values for lists)
- Any nulls in set are ignored.
- Explicit values in remove mean delete this if it is the actual value
- Nulls in remove become like delete * for the corresponding predicate.
See AddRewriter for how the set and remove fragments get created.
func (*UpdateRewriter) RewriteQueries ¶
func (urw *UpdateRewriter) RewriteQueries( ctx context.Context, m schema.Mutation) ([]*dql.GraphQuery, []string, error)
RewriteQueries creates and rewrites set and remove update patches queries. The GraphQL updates look like:
input UpdateAuthorInput {
filter: AuthorFilter!
set: PatchAuthor
remove: PatchAuthor
}
which gets rewritten in to a DQL queries to check if - referenced UIDs and XIDs in set and remove exist or not.
Depending on the result of these executed queries, it is then decided whether to create new nodes or link to existing ones.
Note that queries rewritten using RewriteQueries don't include UIDs or XIDs referenced as part of filter argument.
See AddRewriter for how the rewritten queries look like.
type UpsertMutation ¶
type UpsertMutation struct {
Query []*dql.GraphQuery
Mutations []*dgoapi.Mutation
NewNodes map[string]schema.Type
}
An UpsertMutation is the query and mutations needed for a Dgraph upsert. The node types is a blank node name -> Type mapping of nodes that could be created by the upsert.
type VariableGenerator ¶
type VariableGenerator struct {
// contains filtered or unexported fields
}
A VariableGenerator generates unique variable names.
func NewVariableGenerator ¶
func NewVariableGenerator() *VariableGenerator