plan

package
v2.0.0-rc.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 17, 2024 License: MIT Imports: 22 Imported by: 6

Documentation

Index

Constants

View Source
const (
	ReasonStage1Uniq                  = "stage1: uniq"
	ReasonStage1SameSourceParent      = "stage1: same source parent of uniq node"
	ReasonStage1SameSourceLeafChild   = "stage1: same source leaf child of uniq node"
	ReasonStage1SameSourceLeafSibling = "stage1: same source leaf sibling of uniq node"

	ReasonStage2SameSourceNodeOfSelectedParent  = "stage2: node on the same source as selected parent"
	ReasonStage2SameSourceNodeOfSelectedChild   = "stage2: node on the same source as selected child"
	ReasonStage2SameSourceNodeOfSelectedSibling = "stage2: node on the same source as selected sibling"

	ReasonStage3SelectAvailableNode = "stage3: select first available node"

	ReasonKeyRequirementProvidedByPlanner = "provided by planner as required by @key"
)

Variables

View Source
var (
	FieldDoesntHaveSelectionSetErr          = errors.New("unexpected error: field does not have a selection set")
	InlineFragmentDoesntHaveSelectionSetErr = errors.New("unexpected error: inline fragment does not have a selection set")
	InlineFragmentTypeIsNotExistsErr        = errors.New("unexpected error: inline fragment type condition does not exists")
)

Functions

func AnalyzePlanKind

func AnalyzePlanKind(operation, definition *ast.Document, operationName string) (operationType ast.OperationType, streaming bool, error error)

func RequiredFieldsFragment

func RequiredFieldsFragment(typeName, requiredFields string, includeTypename bool) (*ast.Document, *operationreport.Report)

Types

type ArgumentConfiguration

type ArgumentConfiguration struct {
	Name         string
	SourceType   SourceType
	SourcePath   []string
	RenderConfig ArgumentRenderConfig
	RenameTypeTo string
}

type ArgumentRenderConfig

type ArgumentRenderConfig string

ArgumentRenderConfig is used to determine how an argument should be rendered

const (
	RenderArgumentDefault        ArgumentRenderConfig = ""
	RenderArgumentAsArrayCSV     ArgumentRenderConfig = "render_argument_as_array_csv"
	RenderArgumentAsGraphQLValue ArgumentRenderConfig = "render_argument_as_graphql_value"
	RenderArgumentAsJSONValue    ArgumentRenderConfig = "render_argument_as_json_value"
)

type ArgumentUsageInfo

type ArgumentUsageInfo struct {
	FieldName         string
	EnclosingTypeName string
	ArgumentName      string
	ArgumentTypeName  string
}

type ArgumentsConfigurations

type ArgumentsConfigurations []ArgumentConfiguration

func (ArgumentsConfigurations) ForName

type Configuration

type Configuration struct {
	DefaultFlushIntervalMillis int64
	DataSources                []DataSourceConfiguration
	Fields                     FieldConfigurations
	Types                      TypeConfigurations
	// DisableResolveFieldPositions should be set to true for testing purposes
	// This setting removes position information from all fields
	// In production, this should be set to false so that error messages are easier to understand
	DisableResolveFieldPositions bool
	CustomResolveMap             map[string]resolve.CustomResolve

	// Debug - configure debug options
	Debug DebugConfiguration
	// IncludeInfo will add additional information to the plan,
	// e.g. the origin of a field, possible types, etc.
	// This information is required to compute the schema usage info from a plan
	IncludeInfo bool
}

type DSHash

type DSHash uint64

type DataSourceConfiguration

type DataSourceConfiguration struct {
	// ID is a unique identifier for the DataSource
	ID string
	// RootNodes - defines the nodes where the responsibility of the DataSource begins
	// When you enter a node, and it is not a child node
	// when you have entered into a field which representing data source - it means that we are starting a new planning stage
	RootNodes TypeFields
	// ChildNodes - describes additional fields which will be requested along with fields which has a datasources
	// They are always required for the Graphql datasources cause each field could have its own datasource
	// For any single point datasource like HTTP/REST or GRPC we could not request fewer fields, as we always get a full response
	ChildNodes TypeFields
	Directives DirectiveConfigurations
	Factory    PlannerFactory
	Custom     json.RawMessage

	FederationMetaData FederationMetaData
	// contains filtered or unexported fields
}

func (*DataSourceConfiguration) HasChildNode

func (d *DataSourceConfiguration) HasChildNode(typeName, fieldName string) bool

func (*DataSourceConfiguration) HasChildNodeWithTypename

func (d *DataSourceConfiguration) HasChildNodeWithTypename(typeName string) bool

func (*DataSourceConfiguration) HasKeyRequirement

func (d *DataSourceConfiguration) HasKeyRequirement(typeName, requiresFields string) bool

func (*DataSourceConfiguration) HasRootNode

func (d *DataSourceConfiguration) HasRootNode(typeName, fieldName string) bool

func (*DataSourceConfiguration) HasRootNodeWithTypename

func (d *DataSourceConfiguration) HasRootNodeWithTypename(typeName string) bool

func (*DataSourceConfiguration) Hash

func (d *DataSourceConfiguration) Hash() DSHash

func (*DataSourceConfiguration) RequiredFieldsByKey

func (d *DataSourceConfiguration) RequiredFieldsByKey(typeName string) []FederationFieldConfiguration

func (*DataSourceConfiguration) RequiredFieldsByRequires

func (d *DataSourceConfiguration) RequiredFieldsByRequires(typeName, fieldName string) []FederationFieldConfiguration

type DataSourceDebugger

type DataSourceDebugger interface {
	astvisitor.VisitorIdentifier
	DebugPrint(args ...interface{})
	EnableDebug()
	EnableQueryPlanLogging()
}

type DataSourceFilter

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

func NewDataSourceFilter

func NewDataSourceFilter(operation, definition *ast.Document, report *operationreport.Report) *DataSourceFilter

func (*DataSourceFilter) FilterDataSources

func (f *DataSourceFilter) FilterDataSources(dataSources []DataSourceConfiguration, existingNodes NodeSuggestions, hints ...NodeSuggestionHint) (used []DataSourceConfiguration, suggestions NodeSuggestions)

type DataSourcePlanner

type DataSourcePlanner interface {
	Register(visitor *Visitor, configuration DataSourceConfiguration, dataSourcePlannerConfiguration DataSourcePlannerConfiguration) error
	ConfigureFetch() resolve.FetchConfiguration
	ConfigureSubscription() SubscriptionConfiguration
	DataSourcePlanningBehavior() DataSourcePlanningBehavior
	// DownstreamResponseFieldAlias allows the DataSourcePlanner to overwrite the response path with an alias
	// It's required to set OverrideFieldPathFromAlias to true
	// This function is useful in the following scenario
	// 1. The downstream Query doesn't contain an alias
	// 2. The path configuration rewrites the field to an existing field
	// 3. The DataSourcePlanner is using an alias to the upstream
	// Example:
	//
	// type Query {
	//		country: Country
	//		countryAlias: Country
	// }
	//
	// Both, country and countryAlias have a path in the FieldConfiguration of "country"
	// In theory, they would be treated as the same field
	// However, by using DownstreamResponseFieldAlias, it's possible for the DataSourcePlanner to use an alias for countryAlias.
	// In this case, the response would contain both, country and countryAlias fields in the response.
	// At the same time, the downstream Query would only expect the response on the path "country",
	// as both country and countryAlias have a mapping to the path "country".
	// The DataSourcePlanner could keep track that it rewrites the upstream query and use DownstreamResponseFieldAlias
	// to indicate to the Planner to expect the response for countryAlias on the path "countryAlias" instead of "country".
	DownstreamResponseFieldAlias(downstreamFieldRef int) (alias string, exists bool)
	UpstreamSchema(dataSourceConfig DataSourceConfiguration) *ast.Document
}

type DataSourcePlannerConfiguration

type DataSourcePlannerConfiguration struct {
	RequiredFields FederationFieldConfigurations
	ProvidedFields NodeSuggestions
	ParentPath     string
	PathType       PlannerPathType
	IsNested       bool
}

func (*DataSourcePlannerConfiguration) HasRequiredFields

func (c *DataSourcePlannerConfiguration) HasRequiredFields() bool

type DataSourcePlanningBehavior

type DataSourcePlanningBehavior struct {
	// MergeAliasedRootNodes will reuse a data source for multiple root fields with aliases if true.
	// Example:
	//  {
	//    rootField
	//    alias: rootField
	//  }
	// On dynamic data sources (e.g. GraphQL, SQL, ...) this should return true and for
	// static data sources (e.g. REST, static, GRPC...) it should be false.
	MergeAliasedRootNodes bool
	// OverrideFieldPathFromAlias will let the planner know if the response path should also be aliased (= true)
	// or not (= false)
	// Example:
	//  {
	//    rootField
	//    alias: original
	//  }
	// When true expected response will be { "rootField": ..., "alias": ... }
	// When false expected response will be { "rootField": ..., "original": ... }
	OverrideFieldPathFromAlias bool
	// IncludeTypeNameFields should be set to true if the planner wants to get EnterField & LeaveField events
	// for __typename fields
	IncludeTypeNameFields bool
}

type DebugConfiguration

type DebugConfiguration struct {
	PrintOperationTransformations bool
	PrintOperationEnableASTRefs   bool
	PrintPlanningPaths            bool
	PrintQueryPlans               bool
	PrintNodeSuggestions          bool

	ConfigurationVisitor bool
	PlanningVisitor      bool
	DatasourceVisitor    bool
}

type DirectiveConfiguration

type DirectiveConfiguration struct {
	DirectiveName string
	RenameTo      string
}

type DirectiveConfigurations

type DirectiveConfigurations []DirectiveConfiguration

func (*DirectiveConfigurations) RenameTypeNameOnMatchBytes

func (d *DirectiveConfigurations) RenameTypeNameOnMatchBytes(directiveName []byte) []byte

func (*DirectiveConfigurations) RenameTypeNameOnMatchStr

func (d *DirectiveConfigurations) RenameTypeNameOnMatchStr(directiveName string) string

type EntityInterfaceConfiguration

type EntityInterfaceConfiguration struct {
	InterfaceTypeName string
	ConcreteTypeNames []string
}

type FederationFieldConfiguration

type FederationFieldConfiguration struct {
	TypeName     string
	FieldName    string
	SelectionSet string
}

type FederationFieldConfigurations

type FederationFieldConfigurations []FederationFieldConfiguration

func (FederationFieldConfigurations) FilterByType

func (f FederationFieldConfigurations) FilterByType(typeName string) (out []FederationFieldConfiguration)

func (FederationFieldConfigurations) FilterByTypeAndField

func (f FederationFieldConfigurations) FilterByTypeAndField(typeName, fieldName string) (out []FederationFieldConfiguration)

func (FederationFieldConfigurations) HasSelectionSet

func (f FederationFieldConfigurations) HasSelectionSet(typeName, fieldName, selectionSet string) bool

func (FederationFieldConfigurations) UniqueTypes

func (f FederationFieldConfigurations) UniqueTypes() (out []string)

type FederationMetaData

type FederationMetaData struct {
	Keys             FederationFieldConfigurations
	Requires         FederationFieldConfigurations
	Provides         FederationFieldConfigurations
	EntityInterfaces []EntityInterfaceConfiguration
	InterfaceObjects []EntityInterfaceConfiguration
}

type FieldConfiguration

type FieldConfiguration struct {
	TypeName  string
	FieldName string
	// DisableDefaultMapping - instructs planner whether to use path mapping coming from Path field
	DisableDefaultMapping bool
	// Path - represents a json path to lookup for a field value in response json
	Path      []string
	Arguments ArgumentsConfigurations
	// deprecated: use DataSourceConfiguration.FederationMetaData instead
	RequiresFields []string
	// UnescapeResponseJson set to true will allow fields (String,List,Object)
	// to be resolved from an escaped JSON string
	// e.g. {"response":"{\"foo\":\"bar\"}"} will be returned as {"foo":"bar"} when path is "response"
	// This way, it is possible to resolve a JSON string as part of the response without extra String encoding of the JSON
	UnescapeResponseJson bool
	// HasAuthorizationRule needs to be set to true if the Authorizer should be called for this field
	HasAuthorizationRule bool
}

type FieldConfigurations

type FieldConfigurations []FieldConfiguration

func (FieldConfigurations) ForTypeField

func (f FieldConfigurations) ForTypeField(typeName, fieldName string) *FieldConfiguration

type InputTypeFieldUsageInfo

type InputTypeFieldUsageInfo struct {
	// IsRootVariable is true if the field is a root variable, e.g. $id
	IsRootVariable bool
	// Count is the number of times this field usage was captured, it's usually 1 but can be higher if the field is used multiple times
	Count int
	// FieldName is the name of the field, e.g. "id" for this selection set: { id }
	FieldName string
	// FieldTypeName is the name of the field type, e.g. "ID" for this selection set: { id }
	FieldTypeName string
	// EnclosingTypeNames is a list of all possible enclosing types, e.g. ["User"] for the "id" field: { user { id } }
	EnclosingTypeNames []string
	// IsEnumField is true if the field is an enum
	IsEnumField bool
	// EnumValues is a list of all enum values that were used for this field
	EnumValues []string
}

func (*InputTypeFieldUsageInfo) Equals

type Kind

type Kind int
const (
	SynchronousResponseKind Kind = iota + 1
	SubscriptionResponseKind
)

type NodeSuggestion

type NodeSuggestion struct {
	TypeName       string
	FieldName      string
	DataSourceHash DSHash
	Path           string
	ParentPath     string
	IsRootNode     bool
	// contains filtered or unexported fields
}

func (*NodeSuggestion) String

func (n *NodeSuggestion) String() string

type NodeSuggestionHint

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

type NodeSuggestions

type NodeSuggestions []NodeSuggestion

func (NodeSuggestions) HasSuggestionForPath

func (f NodeSuggestions) HasSuggestionForPath(typeName, fieldName, path string) (dsHash DSHash, ok bool)

func (NodeSuggestions) SuggestionsForPath

func (f NodeSuggestions) SuggestionsForPath(typeName, fieldName, path string) (dsHashes []DSHash)

type PathType

type PathType int
const (
	PathTypeField PathType = iota
	PathTypeFragment
	PathTypeParent
)

type Plan

type Plan interface {
	PlanKind() Kind
	SetFlushInterval(interval int64)
}

type Planner

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

func NewPlanner

func NewPlanner(ctx context.Context, config Configuration) *Planner

NewPlanner creates a new Planner from the Configuration and a ctx object The context.Context object is used to determine the lifecycle of stateful DataSources It's important to note that stateful DataSources must be closed when they are no longer being used Stateful DataSources could be those that initiate a WebSocket connection to an origin, a database client, a streaming client, etc... All DataSources are initiated with the same context.Context object provided to the Planner. To ensure that there are no memory leaks, it's therefore important to add a cancel func or timeout to the context.Context At the time when the resolver and all operations should be garbage collected, ensure to first cancel or timeout the ctx object If you don't cancel the context.Context, the goroutines will run indefinitely and there's no reference left to stop them

func (*Planner) Plan

func (p *Planner) Plan(operation, definition *ast.Document, operationName string, report *operationreport.Report) (plan Plan)

func (*Planner) SetConfig

func (p *Planner) SetConfig(config Configuration)

func (*Planner) SetDebugConfig

func (p *Planner) SetDebugConfig(config DebugConfiguration)

type PlannerFactory

type PlannerFactory interface {
	// Planner should return the DataSourcePlanner
	// closer is the closing channel for all stateful DataSources
	// At runtime, the Execution Engine will be instantiated with one global resolve.Closer.
	// Once the Closer gets closed, all stateful DataSources must close their connections and cleanup themselves.
	// They can do so by starting a goroutine on instantiation time that blocking reads on the resolve.Closer.
	// Once the Closer emits the close event, they have to terminate (e.g. close database connections).
	Planner(ctx context.Context) DataSourcePlanner
}

type PlannerPathType

type PlannerPathType int
const (
	PlannerPathObject PlannerPathType = iota
	PlannerPathArrayItem
	PlannerPathNestedInArray
)

type SchemaUsageInfo

type SchemaUsageInfo struct {
	// OperationType is the type of the operation that was executed, e.g. query, mutation, subscription
	OperationType ast.OperationType
	// TypeFields is a list of all fields that were used to define the response shape
	TypeFields []TypeFieldUsageInfo
	// Arguments is a list of all arguments that were used on response fields
	Arguments []ArgumentUsageInfo
	// InputTypeFields is a list of all fields that were used to define the input shape
	InputTypeFields []InputTypeFieldUsageInfo
}

func GetSchemaUsageInfo

func GetSchemaUsageInfo(plan Plan, operation, definition *ast.Document, variables []byte) (*SchemaUsageInfo, error)

type SourceType

type SourceType string

SourceType is used to determine the source of an argument

const (
	ObjectFieldSource   SourceType = "object_field"
	FieldArgumentSource SourceType = "field_argument"
)

type SubscriptionConfiguration

type SubscriptionConfiguration struct {
	Input          string
	Variables      resolve.Variables
	DataSource     resolve.SubscriptionDataSource
	PostProcessing resolve.PostProcessingConfiguration
}

type SubscriptionResponsePlan

type SubscriptionResponsePlan struct {
	Response      *resolve.GraphQLSubscription
	FlushInterval int64
}

func (*SubscriptionResponsePlan) PlanKind

func (_ *SubscriptionResponsePlan) PlanKind() Kind

func (*SubscriptionResponsePlan) SetFlushInterval

func (s *SubscriptionResponsePlan) SetFlushInterval(interval int64)

type SynchronousResponsePlan

type SynchronousResponsePlan struct {
	Response      *resolve.GraphQLResponse
	FlushInterval int64
}

func (*SynchronousResponsePlan) PlanKind

func (_ *SynchronousResponsePlan) PlanKind() Kind

func (*SynchronousResponsePlan) SetFlushInterval

func (s *SynchronousResponsePlan) SetFlushInterval(interval int64)

type TypeConfiguration

type TypeConfiguration struct {
	TypeName string
	// RenameTo modifies the TypeName
	// so that a downstream Operation can contain a different TypeName than the upstream Schema
	// e.g. if the downstream Operation contains { ... on Human_api { height } }
	// the upstream Operation can be rewritten to { ... on Human { height }}
	// by setting RenameTo to Human
	// This way, Types can be suffixed / renamed in downstream Schemas while keeping the contract with the upstream ok
	RenameTo string
}

type TypeConfigurations

type TypeConfigurations []TypeConfiguration

func (*TypeConfigurations) RenameTypeNameOnMatchBytes

func (t *TypeConfigurations) RenameTypeNameOnMatchBytes(typeName []byte) []byte

func (*TypeConfigurations) RenameTypeNameOnMatchStr

func (t *TypeConfigurations) RenameTypeNameOnMatchStr(typeName string) string

type TypeField

type TypeField struct {
	TypeName   string
	FieldNames []string
}

type TypeFieldSource

type TypeFieldSource struct {
	// IDs is a list of data source IDs that can be used to resolve the field
	IDs []string
}

type TypeFieldUsageInfo

type TypeFieldUsageInfo struct {
	// FieldName is the name of the field, e.g. "id" for this selection set: { id }
	FieldName string
	// FieldTypeName is the name of the field type, e.g. "ID" for this selection set: { id }
	FieldTypeName string
	// EnclosingTypeNames is a list of all possible enclosing types, e.g. ["User"] for the "id" field: { user { id } }
	EnclosingTypeNames []string
	// Path is a list of field names that lead to the field, e.g. ["user", "id"] for this selection set: { user { id } }
	Path []string
	// Source is a list of data source IDs that can be used to resolve the field
	Source TypeFieldSource
}

func (*TypeFieldUsageInfo) Equals

func (t *TypeFieldUsageInfo) Equals(other TypeFieldUsageInfo) bool

type TypeFields

type TypeFields []TypeField

func (TypeFields) HasNode

func (f TypeFields) HasNode(typeName, fieldName string) bool

func (TypeFields) HasNodeWithTypename

func (f TypeFields) HasNodeWithTypename(typeName string) bool

type Visitor

type Visitor struct {
	Operation, Definition *ast.Document
	Walker                *astvisitor.Walker
	Importer              astimport.Importer
	Config                Configuration

	OperationName string
	// contains filtered or unexported fields
}

func (*Visitor) AllowVisitor

func (v *Visitor) AllowVisitor(kind astvisitor.VisitorKind, ref int, visitor interface{}, skipFor astvisitor.SkipVisitors) bool

func (*Visitor) EnterDirective

func (v *Visitor) EnterDirective(ref int)

func (*Visitor) EnterDocument

func (v *Visitor) EnterDocument(operation, definition *ast.Document)

func (*Visitor) EnterField

func (v *Visitor) EnterField(ref int)

func (*Visitor) EnterInlineFragment

func (v *Visitor) EnterInlineFragment(ref int)

func (*Visitor) EnterOperationDefinition

func (v *Visitor) EnterOperationDefinition(ref int)

func (*Visitor) EnterSelectionSet

func (v *Visitor) EnterSelectionSet(ref int)

func (*Visitor) LeaveDocument

func (v *Visitor) LeaveDocument(_, _ *ast.Document)

func (*Visitor) LeaveField

func (v *Visitor) LeaveField(ref int)

func (*Visitor) LeaveInlineFragment

func (v *Visitor) LeaveInlineFragment(ref int)

func (*Visitor) LeaveSelectionSet

func (v *Visitor) LeaveSelectionSet(ref int)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL