Documentation
¶
Overview ¶
Package graphqlschemausage extracts schema usage metrics from GraphQL operations, associating each type, field, argument, and input with the SubgraphIDs that provide them.
Architecture ¶
The challenge: Execution plans optimize for execution, not analysis. Variables are resolved away, and only final field selections remain. To track usage, we must correlate three sources:
- Execution Plan - contains field → subgraph mappings (via Source.IDs)
- Operation AST - contains argument and variable usage
- Variable Values - contains actual input data (nested objects, scalars, etc.)
We extract subgraph IDs by building intermediate mappings:
plan → field paths → variables → input fields
This enables accurate federated schema usage tracking, showing which subgraphs serve which parts of queries, even through variables and deeply nested input objects.
Usage Tracking Types ¶
1. TYPE & FIELD: Direct extraction from execution plan (has Source.IDs) 2. ARGUMENT: Correlate AST arguments with plan field paths 3. INPUT: Build field→subgraph and variable→subgraph maps, then traverse variable values
Input Null Tracking ¶
Input fields are ALWAYS tracked, even when null (explicit or implicit). This is critical for detecting breaking changes when optional fields become required. Each input usage includes an IsNull flag to indicate null propagation. When an input is null, the chain stops there—nested fields are not traversed since the parent is null.
For list-typed fields:
- Null list values (e.g., tags: null where tags: [String]) are tracked with IsNull=true
- Empty lists (e.g., tags: []) are tracked with IsNull=false (field is used, just no elements)
- Null elements within lists (e.g., tags: ["a", null, "b"]) are NOT individually tracked (the field-level usage already indicates the list type is being used)
Design Components ¶
The package uses a unified AST walk with pluggable collectors:
- walkContext: Shared state for AST traversal (path, stacks, documents) - collector: Interface for components that collect data during the walk - unifiedVisitor: Single AST walker that delegates to multiple collectors
Individual collectors handle specific concerns: - variableSubgraphCollector: Maps variables to subgraph IDs - argumentUsageCollector: Collects argument usage metrics - implicitInputCollector: Tracks implicit null input type arguments
This design enables: - Single O(n) AST walk instead of multiple passes - Independent testing of each collector - Easy addition of new collectors without changing walk infrastructure
Index ¶
- func GetArgumentUsageInfo(operation, definition *ast.Document, variables *astjson.Value, ...) ([]*graphqlmetrics.ArgumentUsageInfo, error)
- func GetInputUsageInfo(operation, definition *ast.Document, variables *astjson.Value, ...) ([]*graphqlmetrics.InputUsageInfo, error)
- type TypeFieldMetrics
- type TypeFieldUsageInfo
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GetArgumentUsageInfo ¶
func GetArgumentUsageInfo(operation, definition *ast.Document, variables *astjson.Value, operationPlan plan.Plan, remapVariables map[string]string) ([]*graphqlmetrics.ArgumentUsageInfo, error)
GetArgumentUsageInfo extracts argument usage by correlating AST arguments with execution plan field paths. Includes null tracking for both inline and variable-based argument values.
The variables parameter can be nil, which is treated as "no variables provided". When nil, null detection for variable-based arguments will default to false (cannot determine nullness).
func GetInputUsageInfo ¶
func GetInputUsageInfo(operation, definition *ast.Document, variables *astjson.Value, operationPlan plan.Plan, remapVariables map[string]string) ([]*graphqlmetrics.InputUsageInfo, error)
GetInputUsageInfo extracts input usage by traversing variable values. Tracks both explicit nulls ({"field": null}) and implicit nulls (missing fields) for breaking change detection. Also tracks input usage for implicitly null input type arguments (arguments not provided).
The variables parameter can be nil, which is treated as "no variables provided". When nil, input object types are still tracked with IsNull=true for breaking change detection.
Types ¶
type TypeFieldMetrics ¶
type TypeFieldMetrics []*TypeFieldUsageInfo
An array of TypeFieldUsageInfo, with a method to convert it into a []*graphqlmetrics.TypeFieldUsageInfo
func (TypeFieldMetrics) IntoGraphQLMetrics ¶
func (t TypeFieldMetrics) IntoGraphQLMetrics() []*graphqlmetrics.TypeFieldUsageInfo
IntoGraphQLMetrics converts the TypeFieldMetrics into a []*graphqlmetrics.TypeFieldUsageInfo
type TypeFieldUsageInfo ¶
type TypeFieldUsageInfo struct {
NamedType string
ExactParentTypeName string
Path []string
ParentTypeNames []string
SubgraphIDs []string
IndirectInterfaceField bool
}
TypeFieldUsageInfo holds information about the usage of a GraphQL type
func GetTypeFieldUsageInfo ¶
func GetTypeFieldUsageInfo(operationPlan plan.Plan) []*TypeFieldUsageInfo
GetTypeFieldUsageInfo extracts type and field usage from the execution plan.
func (*TypeFieldUsageInfo) IntoGraphQLMetrics ¶
func (t *TypeFieldUsageInfo) IntoGraphQLMetrics() *graphqlmetrics.TypeFieldUsageInfo
IntoGraphQLMetrics converts the graphqlschemausage.TypeFieldUsageInfo into a *graphqlmetrics.TypeFieldUsageInfo Use TypeFieldMetrics.IntoGraphQLMetrics where possible if processing in bulk, it's faster.