Reputation: 21
Consider a schema like following:
type Users {
name: String
age: Int
Posts: [Post!]
}
type Post {
id: String
title: String
createdAt: Date
}
Now, I want to assign field-specific complexity to the above schema. For e.g. Posts field in the User can have more complexity as it can be a more expensive resolver. Also, the complexity can also depend on the number of posts we request in the query.
The official doc explains how to define custom complexity calculator and assign it to your schema but it doesn't work for my case due to following reasons:
What I’ve Tried
type User {
name: String
age: Int
Posts: [Post!] @complexity(complexityDegree:"5")
}
type ComplexityMetadata struct {
Value int
}
// Extract complexity metadata for fields using introspection on ExecutableSchema
func extractComplexityMetadata(schema graphql.ExecutableSchema) map[string]ComplexityMetadata {
metadata := make(map[string]ComplexityMetadata)
// Access the underlying schema from ExecutableSchema
underlyingSchema := schema.Schema()
// Convert from gqlparser's AST schema to introspection schema (from gqlgen)
collectComplexityMetadata(underlyingSchema, metadata, "")
return metadata
}
func collectComplexityMetadata(schema *ast.Schema, metadata map[string]ComplexityMetadata, parentType string) {
for _, typ := range schema.Types {
// Skip non-object types and built-in GraphQL types
log.Info("collecting complexity metadata", "type", typ.Name, "kind", typ.Kind)
if typ.Kind != ast.Object {
continue
}
// Iterate over fields in this type
for _, field := range typ.Fields {
fieldName := fmt.Sprintf("%s.%s", parentType, field.Name)
// Check if this field has a `complexity` directive
for _, directive := range field.Directives {
if directive.Name == "complexity" {
// Extract the directive arguments (value and pageSizeFactor)
valueArg := directive.Arguments.ForName("complexityDegree")
complexityValue := 1 // Default complexity value
if valueArg != nil {
complexityValue, _ = strconv.Atoi(valueArg.Value.Raw)
}
// Store the metadata using a string key (TypeName.FieldName)
metadata[fieldName] = ComplexityMetadata{
Value: complexityValue,
}
}
}
// If the field's type is an object type, recurse into it
if field.Type.NamedType != "" && schema.Types[field.Type.NamedType].Kind == ast.Object {
// Recurse into the nested type and collect its fields
log.Info("recursing into nested type", "field", fieldName, "type", field.Type.NamedType)
collectComplexityMetadata(schema, metadata, fieldName)
}
}
}
}
This approach performs badly on large schema and takes too much time (8-10 minutes). gqlgen's official doc mentions assigning the function one by one to your schema. This is impractical in the case of a huge schema.
I want to dynamically assign custom complexity calculator to all types in the schema. Ideally in a way that doesn't take several minutes to process.
Upvotes: 2
Views: 74